Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(172)

Side by Side Diff: ipc/ipc_channel_proxy.cc

Issue 183553004: Eliminate a potential race in IPC::ChannelProxy (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: merge Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ipc/ipc_channel_proxy.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/bind.h" 5 #include "base/bind.h"
6 #include "base/compiler_specific.h" 6 #include "base/compiler_specific.h"
7 #include "base/debug/trace_event.h" 7 #include "base/debug/trace_event.h"
8 #include "base/location.h" 8 #include "base/location.h"
9 #include "base/memory/ref_counted.h" 9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 149
150 ChannelProxy::Context::~Context() { 150 ChannelProxy::Context::~Context() {
151 } 151 }
152 152
153 void ChannelProxy::Context::ClearIPCTaskRunner() { 153 void ChannelProxy::Context::ClearIPCTaskRunner() {
154 ipc_task_runner_ = NULL; 154 ipc_task_runner_ = NULL;
155 } 155 }
156 156
157 void ChannelProxy::Context::CreateChannel(const IPC::ChannelHandle& handle, 157 void ChannelProxy::Context::CreateChannel(const IPC::ChannelHandle& handle,
158 const Channel::Mode& mode) { 158 const Channel::Mode& mode) {
159 DCHECK(channel_.get() == NULL); 159 DCHECK(!channel_);
160 channel_id_ = handle.name; 160 channel_id_ = handle.name;
161 channel_.reset(new Channel(handle, mode, this)); 161 channel_.reset(new Channel(handle, mode, this));
162 } 162 }
163 163
164 bool ChannelProxy::Context::TryFilters(const Message& message) { 164 bool ChannelProxy::Context::TryFilters(const Message& message) {
165 DCHECK(message_filter_router_); 165 DCHECK(message_filter_router_);
166 #ifdef IPC_MESSAGE_LOG_ENABLED 166 #ifdef IPC_MESSAGE_LOG_ENABLED
167 Logging* logger = Logging::GetInstance(); 167 Logging* logger = Logging::GetInstance();
168 if (logger->Enabled()) 168 if (logger->Enabled())
169 logger->OnPreDispatchMessage(message); 169 logger->OnPreDispatchMessage(message);
(...skipping 19 matching lines...) Expand all
189 189
190 // Called on the IPC::Channel thread 190 // Called on the IPC::Channel thread
191 bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) { 191 bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
192 listener_task_runner_->PostTask( 192 listener_task_runner_->PostTask(
193 FROM_HERE, base::Bind(&Context::OnDispatchMessage, this, message)); 193 FROM_HERE, base::Bind(&Context::OnDispatchMessage, this, message));
194 return true; 194 return true;
195 } 195 }
196 196
197 // Called on the IPC::Channel thread 197 // Called on the IPC::Channel thread
198 void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) { 198 void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) {
199 // We cache off the peer_pid so it can be safely accessed from both threads.
200 peer_pid_ = channel_->peer_pid();
201
199 // Add any pending filters. This avoids a race condition where someone 202 // Add any pending filters. This avoids a race condition where someone
200 // creates a ChannelProxy, calls AddFilter, and then right after starts the 203 // creates a ChannelProxy, calls AddFilter, and then right after starts the
201 // peer process. The IO thread could receive a message before the task to add 204 // peer process. The IO thread could receive a message before the task to add
202 // the filter is run on the IO thread. 205 // the filter is run on the IO thread.
203 OnAddFilter(); 206 OnAddFilter();
204 207
205 // We cache off the peer_pid so it can be safely accessed from both threads.
206 peer_pid_ = channel_->peer_pid();
207 for (size_t i = 0; i < filters_.size(); ++i)
208 filters_[i]->OnChannelConnected(peer_pid);
209
210 // See above comment about using listener_task_runner_ here. 208 // See above comment about using listener_task_runner_ here.
211 listener_task_runner_->PostTask( 209 listener_task_runner_->PostTask(
212 FROM_HERE, base::Bind(&Context::OnDispatchConnected, this)); 210 FROM_HERE, base::Bind(&Context::OnDispatchConnected, this));
213 } 211 }
214 212
215 // Called on the IPC::Channel thread 213 // Called on the IPC::Channel thread
216 void ChannelProxy::Context::OnChannelError() { 214 void ChannelProxy::Context::OnChannelError() {
217 for (size_t i = 0; i < filters_.size(); ++i) 215 for (size_t i = 0; i < filters_.size(); ++i)
218 filters_[i]->OnChannelError(); 216 filters_[i]->OnChannelError();
219 217
(...skipping 16 matching lines...) Expand all
236 } 234 }
237 235
238 for (size_t i = 0; i < filters_.size(); ++i) 236 for (size_t i = 0; i < filters_.size(); ++i)
239 filters_[i]->OnFilterAdded(channel_.get()); 237 filters_[i]->OnFilterAdded(channel_.get());
240 } 238 }
241 239
242 // Called on the IPC::Channel thread 240 // Called on the IPC::Channel thread
243 void ChannelProxy::Context::OnChannelClosed() { 241 void ChannelProxy::Context::OnChannelClosed() {
244 // It's okay for IPC::ChannelProxy::Close to be called more than once, which 242 // It's okay for IPC::ChannelProxy::Close to be called more than once, which
245 // would result in this branch being taken. 243 // would result in this branch being taken.
246 if (!channel_.get()) 244 if (!channel_)
247 return; 245 return;
248 246
249 for (size_t i = 0; i < filters_.size(); ++i) { 247 for (size_t i = 0; i < filters_.size(); ++i) {
250 filters_[i]->OnChannelClosing(); 248 filters_[i]->OnChannelClosing();
251 filters_[i]->OnFilterRemoved(); 249 filters_[i]->OnFilterRemoved();
252 } 250 }
253 251
254 // We don't need the filters anymore. 252 // We don't need the filters anymore.
255 message_filter_router_->Clear(); 253 message_filter_router_->Clear();
256 filters_.clear(); 254 filters_.clear();
255 // We don't need the lock, because at this point, the listener thread can't
256 // access it any more.
257 pending_filters_.clear();
257 258
258 channel_.reset(); 259 channel_.reset();
259 260
260 // Balance with the reference taken during startup. This may result in 261 // Balance with the reference taken during startup. This may result in
261 // self-destruction. 262 // self-destruction.
262 Release(); 263 Release();
263 } 264 }
264 265
265 void ChannelProxy::Context::Clear() { 266 void ChannelProxy::Context::Clear() {
266 listener_ = NULL; 267 listener_ = NULL;
267 } 268 }
268 269
269 // Called on the IPC::Channel thread 270 // Called on the IPC::Channel thread
270 void ChannelProxy::Context::OnSendMessage(scoped_ptr<Message> message) { 271 void ChannelProxy::Context::OnSendMessage(scoped_ptr<Message> message) {
271 if (!channel_.get()) { 272 if (!channel_) {
272 OnChannelClosed(); 273 OnChannelClosed();
273 return; 274 return;
274 } 275 }
276
275 if (!channel_->Send(message.release())) 277 if (!channel_->Send(message.release()))
276 OnChannelError(); 278 OnChannelError();
277 } 279 }
278 280
279 // Called on the IPC::Channel thread 281 // Called on the IPC::Channel thread
280 void ChannelProxy::Context::OnAddFilter() { 282 void ChannelProxy::Context::OnAddFilter() {
283 // Our OnChannelConnected method has not yet been called, so we can't be
284 // sure that channel_ is valid yet. When OnChannelConnected *is* called,
285 // it invokes OnAddFilter, so any pending filter(s) will be added at that
286 // time.
287 if (peer_pid_ == base::kNullProcessId)
288 return;
289
281 std::vector<scoped_refptr<MessageFilter> > new_filters; 290 std::vector<scoped_refptr<MessageFilter> > new_filters;
282 { 291 {
283 base::AutoLock auto_lock(pending_filters_lock_); 292 base::AutoLock auto_lock(pending_filters_lock_);
284 new_filters.swap(pending_filters_); 293 new_filters.swap(pending_filters_);
285 } 294 }
286 295
287 for (size_t i = 0; i < new_filters.size(); ++i) { 296 for (size_t i = 0; i < new_filters.size(); ++i) {
288 filters_.push_back(new_filters[i]); 297 filters_.push_back(new_filters[i]);
289 298
290 message_filter_router_->AddFilter(new_filters[i].get()); 299 message_filter_router_->AddFilter(new_filters[i].get());
291 300
292 // If the channel has already been created, then we need to send this 301 // The channel has already been created and connected, so we need to
293 // message so that the filter gets access to the Channel. 302 // inform the filters right now.
294 if (channel_.get()) 303 new_filters[i]->OnFilterAdded(channel_.get());
295 new_filters[i]->OnFilterAdded(channel_.get()); 304 new_filters[i]->OnChannelConnected(peer_pid_);
296 // Ditto for if the channel has been connected.
297 if (peer_pid_)
298 new_filters[i]->OnChannelConnected(peer_pid_);
299 } 305 }
300 } 306 }
301 307
302 // Called on the IPC::Channel thread 308 // Called on the IPC::Channel thread
303 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) { 309 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
304 if (!channel_.get()) 310 if (peer_pid_ == base::kNullProcessId) {
311 // The channel is not yet connected, so any filters are still pending.
312 base::AutoLock auto_lock(pending_filters_lock_);
313 for (size_t i = 0; i < pending_filters_.size(); ++i) {
314 if (pending_filters_[i].get() == filter) {
315 filter->OnFilterRemoved();
316 pending_filters_.erase(pending_filters_.begin() + i);
317 return;
318 }
319 }
320 return;
321 }
322 if (!channel_)
305 return; // The filters have already been deleted. 323 return; // The filters have already been deleted.
306 324
307 message_filter_router_->RemoveFilter(filter); 325 message_filter_router_->RemoveFilter(filter);
308 326
309 for (size_t i = 0; i < filters_.size(); ++i) { 327 for (size_t i = 0; i < filters_.size(); ++i) {
310 if (filters_[i].get() == filter) { 328 if (filters_[i].get() == filter) {
311 filter->OnFilterRemoved(); 329 filter->OnFilterRemoved();
312 filters_.erase(filters_.begin() + i); 330 filters_.erase(filters_.begin() + i);
313 return; 331 return;
314 } 332 }
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
512 Channel* channel = context_.get()->channel_.get(); 530 Channel* channel = context_.get()->channel_.get();
513 // Channel must have been created first. 531 // Channel must have been created first.
514 DCHECK(channel) << context_.get()->channel_id_; 532 DCHECK(channel) << context_.get()->channel_id_;
515 return channel->GetPeerEuid(peer_euid); 533 return channel->GetPeerEuid(peer_euid);
516 } 534 }
517 #endif 535 #endif
518 536
519 //----------------------------------------------------------------------------- 537 //-----------------------------------------------------------------------------
520 538
521 } // namespace IPC 539 } // namespace IPC
OLDNEW
« no previous file with comments | « ipc/ipc_channel_proxy.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698