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

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: Clarify comment. 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();
257 255
258 channel_.reset(); 256 channel_.reset();
259 257
260 // Balance with the reference taken during startup. This may result in 258 // Balance with the reference taken during startup. This may result in
261 // self-destruction. 259 // self-destruction.
262 Release(); 260 Release();
263 } 261 }
264 262
265 void ChannelProxy::Context::Clear() { 263 void ChannelProxy::Context::Clear() {
266 listener_ = NULL; 264 listener_ = NULL;
267 } 265 }
268 266
269 // Called on the IPC::Channel thread 267 // Called on the IPC::Channel thread
270 void ChannelProxy::Context::OnSendMessage(scoped_ptr<Message> message) { 268 void ChannelProxy::Context::OnSendMessage(scoped_ptr<Message> message) {
271 if (!channel_.get()) { 269 if (!channel_)
272 OnChannelClosed();
273 return; 270 return;
dmichael (off chromium) 2014/02/28 23:25:47 There's no need to call OnChannelClosed; it's alre
274 } 271
275 if (!channel_->Send(message.release())) 272 if (!channel_->Send(message.release()))
276 OnChannelError(); 273 OnChannelError();
277 } 274 }
278 275
279 // Called on the IPC::Channel thread 276 // Called on the IPC::Channel thread
280 void ChannelProxy::Context::OnAddFilter() { 277 void ChannelProxy::Context::OnAddFilter() {
278 // Our OnChannelConnected method has not yet been called, so we can't be
279 // sure that channel_ is valid yet. When OnChannelConnected *is* called,
280 // it invokes OnAddFilter, so any pending filter(s) will be added at that
281 // time.
282 if (peer_pid_ == base::kNullProcessId)
283 return;
284
281 std::vector<scoped_refptr<MessageFilter> > new_filters; 285 std::vector<scoped_refptr<MessageFilter> > new_filters;
282 { 286 {
283 base::AutoLock auto_lock(pending_filters_lock_); 287 base::AutoLock auto_lock(pending_filters_lock_);
284 new_filters.swap(pending_filters_); 288 new_filters.swap(pending_filters_);
285 } 289 }
290 if (!channel_)
291 return; // The channel has been closed, so don't really add the filters.
jam 2014/03/03 16:27:03 can this condition really get hit since we're only
dmichael (off chromium) 2014/03/03 16:37:02 Good point, looks like it can't happen now. I'll
286 292
287 for (size_t i = 0; i < new_filters.size(); ++i) { 293 for (size_t i = 0; i < new_filters.size(); ++i) {
288 filters_.push_back(new_filters[i]); 294 filters_.push_back(new_filters[i]);
289 295
290 message_filter_router_->AddFilter(new_filters[i].get()); 296 message_filter_router_->AddFilter(new_filters[i].get());
291 297
292 // If the channel has already been created, then we need to send this 298 // The channel has already been created and connected, so we need to
293 // message so that the filter gets access to the Channel. 299 // inform the filters right now.
294 if (channel_.get()) 300 new_filters[i]->OnFilterAdded(channel_.get());
295 new_filters[i]->OnFilterAdded(channel_.get()); 301 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 } 302 }
300 } 303 }
301 304
302 // Called on the IPC::Channel thread 305 // Called on the IPC::Channel thread
303 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) { 306 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
304 if (!channel_.get()) 307 if (peer_pid_ == base::kNullProcessId) {
308 // The channel is not yet connected, so any filters are still pending.
309 base::AutoLock auto_lock(pending_filters_lock_);
310 for (size_t i = 0; i < pending_filters_.size(); ++i) {
311 if (pending_filters_[i].get() == filter) {
312 filter->OnFilterRemoved();
313 pending_filters_.erase(pending_filters_.begin() + i);
314 return;
315 }
316 }
317 return;
318 }
319 if (!channel_)
305 return; // The filters have already been deleted. 320 return; // The filters have already been deleted.
306 321
307 message_filter_router_->RemoveFilter(filter); 322 message_filter_router_->RemoveFilter(filter);
308 323
309 for (size_t i = 0; i < filters_.size(); ++i) { 324 for (size_t i = 0; i < filters_.size(); ++i) {
310 if (filters_[i].get() == filter) { 325 if (filters_[i].get() == filter) {
311 filter->OnFilterRemoved(); 326 filter->OnFilterRemoved();
312 filters_.erase(filters_.begin() + i); 327 filters_.erase(filters_.begin() + i);
313 return; 328 return;
314 } 329 }
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
512 Channel* channel = context_.get()->channel_.get(); 527 Channel* channel = context_.get()->channel_.get();
513 // Channel must have been created first. 528 // Channel must have been created first.
514 DCHECK(channel) << context_.get()->channel_id_; 529 DCHECK(channel) << context_.get()->channel_id_;
515 return channel->GetPeerEuid(peer_euid); 530 return channel->GetPeerEuid(peer_euid);
516 } 531 }
517 #endif 532 #endif
518 533
519 //----------------------------------------------------------------------------- 534 //-----------------------------------------------------------------------------
520 535
521 } // namespace IPC 536 } // 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