1*635a8641SAndroid Build Coastguard WorkerFrom 9ae1384af2cdd16539e9caaed69b095737e2c272 Mon Sep 17 00:00:00 2001 2*635a8641SAndroid Build Coastguard WorkerFrom: Qijiang Fan <[email protected]> 3*635a8641SAndroid Build Coastguard WorkerDate: Tue, 17 Dec 2019 17:32:35 +0900 4*635a8641SAndroid Build Coastguard WorkerSubject: [PATCH] backport upstream patch to fix watcher leak. 5*635a8641SAndroid Build Coastguard Worker 6*635a8641SAndroid Build Coastguard Workerhttps://chromium-review.googlesource.com/c/chromium/src/+/695914 7*635a8641SAndroid Build Coastguard Worker 8*635a8641SAndroid Build Coastguard WorkerChange-Id: I91928fc00e9845ff75c49c272ff774ff9810f4eb 9*635a8641SAndroid Build Coastguard Worker--- 10*635a8641SAndroid Build Coastguard Worker base/files/file_descriptor_watcher_posix.cc | 104 +++++++++++++++----- 11*635a8641SAndroid Build Coastguard Worker base/threading/thread_restrictions.h | 4 + 12*635a8641SAndroid Build Coastguard Worker 2 files changed, 82 insertions(+), 26 deletions(-) 13*635a8641SAndroid Build Coastguard Worker 14*635a8641SAndroid Build Coastguard Workerdiff --git a/base/files/file_descriptor_watcher_posix.cc b/base/files/file_descriptor_watcher_posix.cc 15*635a8641SAndroid Build Coastguard Workerindex b26bf6c..98d2cec 100644 16*635a8641SAndroid Build Coastguard Worker--- a/base/files/file_descriptor_watcher_posix.cc 17*635a8641SAndroid Build Coastguard Worker+++ b/base/files/file_descriptor_watcher_posix.cc 18*635a8641SAndroid Build Coastguard Worker@@ -5,6 +5,7 @@ 19*635a8641SAndroid Build Coastguard Worker #include "base/files/file_descriptor_watcher_posix.h" 20*635a8641SAndroid Build Coastguard Worker 21*635a8641SAndroid Build Coastguard Worker #include "base/bind.h" 22*635a8641SAndroid Build Coastguard Worker+#include "base/callback_helpers.h" 23*635a8641SAndroid Build Coastguard Worker #include "base/lazy_instance.h" 24*635a8641SAndroid Build Coastguard Worker #include "base/logging.h" 25*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h" 26*635a8641SAndroid Build Coastguard Worker@@ -12,6 +13,7 @@ 27*635a8641SAndroid Build Coastguard Worker #include "base/message_loop/message_pump_for_io.h" 28*635a8641SAndroid Build Coastguard Worker #include "base/sequenced_task_runner.h" 29*635a8641SAndroid Build Coastguard Worker #include "base/single_thread_task_runner.h" 30*635a8641SAndroid Build Coastguard Worker+#include "base/synchronization/waitable_event.h" 31*635a8641SAndroid Build Coastguard Worker #include "base/threading/sequenced_task_runner_handle.h" 32*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_checker.h" 33*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_local.h" 34*635a8641SAndroid Build Coastguard Worker@@ -27,21 +29,7 @@ LazyInstance<ThreadLocalPointer<MessageLoopForIO>>::Leaky 35*635a8641SAndroid Build Coastguard Worker 36*635a8641SAndroid Build Coastguard Worker } // namespace 37*635a8641SAndroid Build Coastguard Worker 38*635a8641SAndroid Build Coastguard Worker-FileDescriptorWatcher::Controller::~Controller() { 39*635a8641SAndroid Build Coastguard Worker- DCHECK(sequence_checker_.CalledOnValidSequence()); 40*635a8641SAndroid Build Coastguard Worker- 41*635a8641SAndroid Build Coastguard Worker- // Delete |watcher_| on the MessageLoopForIO. 42*635a8641SAndroid Build Coastguard Worker- // 43*635a8641SAndroid Build Coastguard Worker- // If the MessageLoopForIO is deleted before Watcher::StartWatching() runs, 44*635a8641SAndroid Build Coastguard Worker- // |watcher_| is leaked. If the MessageLoopForIO is deleted after 45*635a8641SAndroid Build Coastguard Worker- // Watcher::StartWatching() runs but before the DeleteSoon task runs, 46*635a8641SAndroid Build Coastguard Worker- // |watcher_| is deleted from Watcher::WillDestroyCurrentMessageLoop(). 47*635a8641SAndroid Build Coastguard Worker- message_loop_for_io_task_runner_->DeleteSoon(FROM_HERE, watcher_.release()); 48*635a8641SAndroid Build Coastguard Worker- 49*635a8641SAndroid Build Coastguard Worker- // Since WeakPtrs are invalidated by the destructor, RunCallback() won't be 50*635a8641SAndroid Build Coastguard Worker- // invoked after this returns. 51*635a8641SAndroid Build Coastguard Worker-} 52*635a8641SAndroid Build Coastguard Worker- 53*635a8641SAndroid Build Coastguard Worker+// Move watcher above to prevent delete incomplete type at delete watcher later. 54*635a8641SAndroid Build Coastguard Worker class FileDescriptorWatcher::Controller::Watcher 55*635a8641SAndroid Build Coastguard Worker : public MessagePumpForIO::FdWatcher, 56*635a8641SAndroid Build Coastguard Worker public MessageLoopCurrent::DestructionObserver { 57*635a8641SAndroid Build Coastguard Worker@@ -90,6 +78,58 @@ class FileDescriptorWatcher::Controller::Watcher 58*635a8641SAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(Watcher); 59*635a8641SAndroid Build Coastguard Worker }; 60*635a8641SAndroid Build Coastguard Worker 61*635a8641SAndroid Build Coastguard Worker+FileDescriptorWatcher::Controller::~Controller() { 62*635a8641SAndroid Build Coastguard Worker+ DCHECK(sequence_checker_.CalledOnValidSequence()); 63*635a8641SAndroid Build Coastguard Worker+ 64*635a8641SAndroid Build Coastguard Worker+ if (message_loop_for_io_task_runner_->BelongsToCurrentThread()) { 65*635a8641SAndroid Build Coastguard Worker+ // If the MessageLoopForIO and the Controller live on the same thread. 66*635a8641SAndroid Build Coastguard Worker+ watcher_.reset(); 67*635a8641SAndroid Build Coastguard Worker+ } else { 68*635a8641SAndroid Build Coastguard Worker+ // Synchronously wait until |watcher_| is deleted on the MessagePumpForIO 69*635a8641SAndroid Build Coastguard Worker+ // thread. This ensures that the file descriptor is never accessed after 70*635a8641SAndroid Build Coastguard Worker+ // this destructor returns. 71*635a8641SAndroid Build Coastguard Worker+ // 72*635a8641SAndroid Build Coastguard Worker+ // Use a ScopedClosureRunner to ensure that |done| is signaled even if the 73*635a8641SAndroid Build Coastguard Worker+ // thread doesn't run any more tasks (if PostTask returns true, it means 74*635a8641SAndroid Build Coastguard Worker+ // that the task was queued, but it doesn't mean that a RunLoop will run the 75*635a8641SAndroid Build Coastguard Worker+ // task before the queue is deleted). 76*635a8641SAndroid Build Coastguard Worker+ // 77*635a8641SAndroid Build Coastguard Worker+ // We considered associating "generations" to file descriptors to avoid the 78*635a8641SAndroid Build Coastguard Worker+ // synchronous wait. For example, if the IO thread gets a "cancel" for fd=6, 79*635a8641SAndroid Build Coastguard Worker+ // generation=1 after getting a "start watching" for fd=6, generation=2, it 80*635a8641SAndroid Build Coastguard Worker+ // can ignore the "Cancel". However, "generations" didn't solve this race: 81*635a8641SAndroid Build Coastguard Worker+ // 82*635a8641SAndroid Build Coastguard Worker+ // T1 (client) Start watching fd = 6 with WatchReadable() 83*635a8641SAndroid Build Coastguard Worker+ // Stop watching fd = 6 84*635a8641SAndroid Build Coastguard Worker+ // Close fd = 6 85*635a8641SAndroid Build Coastguard Worker+ // Open a new file, fd = 6 gets reused. 86*635a8641SAndroid Build Coastguard Worker+ // T2 (io) Watcher::StartWatching() 87*635a8641SAndroid Build Coastguard Worker+ // Incorrectly starts watching fd = 6 which now refers to a 88*635a8641SAndroid Build Coastguard Worker+ // different file than when WatchReadable() was called. 89*635a8641SAndroid Build Coastguard Worker+ WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL, 90*635a8641SAndroid Build Coastguard Worker+ WaitableEvent::InitialState::NOT_SIGNALED); 91*635a8641SAndroid Build Coastguard Worker+ message_loop_for_io_task_runner_->PostTask( 92*635a8641SAndroid Build Coastguard Worker+ FROM_HERE, BindOnce( 93*635a8641SAndroid Build Coastguard Worker+ [](Watcher *watcher, ScopedClosureRunner closure) { 94*635a8641SAndroid Build Coastguard Worker+ // Since |watcher| is a raw pointer, it isn't deleted 95*635a8641SAndroid Build Coastguard Worker+ // if this callback is deleted before it gets to run. 96*635a8641SAndroid Build Coastguard Worker+ delete watcher; 97*635a8641SAndroid Build Coastguard Worker+ // |closure| runs at the end of this scope. 98*635a8641SAndroid Build Coastguard Worker+ }, 99*635a8641SAndroid Build Coastguard Worker+ Unretained(watcher_.release()), 100*635a8641SAndroid Build Coastguard Worker+ // TODO(fqj): change to BindOnce after some uprev. 101*635a8641SAndroid Build Coastguard Worker+ ScopedClosureRunner(Bind(&WaitableEvent::Signal, 102*635a8641SAndroid Build Coastguard Worker+ Unretained(&done))))); 103*635a8641SAndroid Build Coastguard Worker+ // TODO(fqj): change to ScopedAllowBaseSyncPrimitivesOutsideBlockingScope 104*635a8641SAndroid Build Coastguard Worker+ // after uprev to r586297 105*635a8641SAndroid Build Coastguard Worker+ base::ThreadRestrictions::ScopedAllowWait allow_wait __attribute__((unused)); 106*635a8641SAndroid Build Coastguard Worker+ done.Wait(); 107*635a8641SAndroid Build Coastguard Worker+ } 108*635a8641SAndroid Build Coastguard Worker+ 109*635a8641SAndroid Build Coastguard Worker+ // Since WeakPtrs are invalidated by the destructor, RunCallback() won't be 110*635a8641SAndroid Build Coastguard Worker+ // invoked after this returns. 111*635a8641SAndroid Build Coastguard Worker+} 112*635a8641SAndroid Build Coastguard Worker+ 113*635a8641SAndroid Build Coastguard Worker FileDescriptorWatcher::Controller::Watcher::Watcher( 114*635a8641SAndroid Build Coastguard Worker WeakPtr<Controller> controller, 115*635a8641SAndroid Build Coastguard Worker MessagePumpForIO::Mode mode, 116*635a8641SAndroid Build Coastguard Worker@@ -150,11 +190,19 @@ void FileDescriptorWatcher::Controller::Watcher:: 117*635a8641SAndroid Build Coastguard Worker WillDestroyCurrentMessageLoop() { 118*635a8641SAndroid Build Coastguard Worker DCHECK(thread_checker_.CalledOnValidThread()); 119*635a8641SAndroid Build Coastguard Worker 120*635a8641SAndroid Build Coastguard Worker- // A Watcher is owned by a Controller. When the Controller is deleted, it 121*635a8641SAndroid Build Coastguard Worker- // transfers ownership of the Watcher to a delete task posted to the 122*635a8641SAndroid Build Coastguard Worker- // MessageLoopForIO. If the MessageLoopForIO is deleted before the delete task 123*635a8641SAndroid Build Coastguard Worker- // runs, the following line takes care of deleting the Watcher. 124*635a8641SAndroid Build Coastguard Worker- delete this; 125*635a8641SAndroid Build Coastguard Worker+ if (callback_task_runner_->RunsTasksInCurrentSequence()) { 126*635a8641SAndroid Build Coastguard Worker+ // |controller_| can be accessed directly when Watcher runs on the same 127*635a8641SAndroid Build Coastguard Worker+ // thread. 128*635a8641SAndroid Build Coastguard Worker+ controller_->watcher_.reset(); 129*635a8641SAndroid Build Coastguard Worker+ } else { 130*635a8641SAndroid Build Coastguard Worker+ // If the Watcher and the Controller live on different threads, delete 131*635a8641SAndroid Build Coastguard Worker+ // |this| synchronously. Pending tasks bound to an unretained Watcher* will 132*635a8641SAndroid Build Coastguard Worker+ // not run since this loop is dead. The associated Controller still 133*635a8641SAndroid Build Coastguard Worker+ // technically owns this via unique_ptr but it never uses it directly and 134*635a8641SAndroid Build Coastguard Worker+ // will ultimately send it to this thread for deletion (and that also won't 135*635a8641SAndroid Build Coastguard Worker+ // run since the loop being dead). 136*635a8641SAndroid Build Coastguard Worker+ delete this; 137*635a8641SAndroid Build Coastguard Worker+ } 138*635a8641SAndroid Build Coastguard Worker } 139*635a8641SAndroid Build Coastguard Worker 140*635a8641SAndroid Build Coastguard Worker FileDescriptorWatcher::Controller::Controller(MessagePumpForIO::Mode mode, 141*635a8641SAndroid Build Coastguard Worker@@ -172,12 +220,16 @@ FileDescriptorWatcher::Controller::Controller(MessagePumpForIO::Mode mode, 142*635a8641SAndroid Build Coastguard Worker 143*635a8641SAndroid Build Coastguard Worker void FileDescriptorWatcher::Controller::StartWatching() { 144*635a8641SAndroid Build Coastguard Worker DCHECK(sequence_checker_.CalledOnValidSequence()); 145*635a8641SAndroid Build Coastguard Worker- // It is safe to use Unretained() below because |watcher_| can only be deleted 146*635a8641SAndroid Build Coastguard Worker- // by a delete task posted to |message_loop_for_io_task_runner_| by this 147*635a8641SAndroid Build Coastguard Worker- // Controller's destructor. Since this delete task hasn't been posted yet, it 148*635a8641SAndroid Build Coastguard Worker- // can't run before the task posted below. 149*635a8641SAndroid Build Coastguard Worker- message_loop_for_io_task_runner_->PostTask( 150*635a8641SAndroid Build Coastguard Worker- FROM_HERE, BindOnce(&Watcher::StartWatching, Unretained(watcher_.get()))); 151*635a8641SAndroid Build Coastguard Worker+ if (message_loop_for_io_task_runner_->BelongsToCurrentThread()) { 152*635a8641SAndroid Build Coastguard Worker+ watcher_->StartWatching(); 153*635a8641SAndroid Build Coastguard Worker+ } else { 154*635a8641SAndroid Build Coastguard Worker+ // It is safe to use Unretained() below because |watcher_| can only be deleted 155*635a8641SAndroid Build Coastguard Worker+ // by a delete task posted to |message_loop_for_io_task_runner_| by this 156*635a8641SAndroid Build Coastguard Worker+ // Controller's destructor. Since this delete task hasn't been posted yet, it 157*635a8641SAndroid Build Coastguard Worker+ // can't run before the task posted below. 158*635a8641SAndroid Build Coastguard Worker+ message_loop_for_io_task_runner_->PostTask( 159*635a8641SAndroid Build Coastguard Worker+ FROM_HERE, Bind(&Watcher::StartWatching, Unretained(watcher_.get()))); 160*635a8641SAndroid Build Coastguard Worker+ } 161*635a8641SAndroid Build Coastguard Worker } 162*635a8641SAndroid Build Coastguard Worker 163*635a8641SAndroid Build Coastguard Worker void FileDescriptorWatcher::Controller::RunCallback() { 164*635a8641SAndroid Build Coastguard Workerdiff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h 165*635a8641SAndroid Build Coastguard Workerindex 705ba4d..7532f85 100644 166*635a8641SAndroid Build Coastguard Worker--- a/base/threading/thread_restrictions.h 167*635a8641SAndroid Build Coastguard Worker+++ b/base/threading/thread_restrictions.h 168*635a8641SAndroid Build Coastguard Worker@@ -147,6 +147,7 @@ namespace internal { 169*635a8641SAndroid Build Coastguard Worker class TaskTracker; 170*635a8641SAndroid Build Coastguard Worker } 171*635a8641SAndroid Build Coastguard Worker 172*635a8641SAndroid Build Coastguard Worker+class FileDescriptorWatcher; 173*635a8641SAndroid Build Coastguard Worker class GetAppOutputScopedAllowBaseSyncPrimitives; 174*635a8641SAndroid Build Coastguard Worker class SimpleThread; 175*635a8641SAndroid Build Coastguard Worker class StackSamplingProfiler; 176*635a8641SAndroid Build Coastguard Worker@@ -479,6 +480,9 @@ class BASE_EXPORT ThreadRestrictions { 177*635a8641SAndroid Build Coastguard Worker friend class ui::CommandBufferLocal; 178*635a8641SAndroid Build Coastguard Worker friend class ui::GpuState; 179*635a8641SAndroid Build Coastguard Worker 180*635a8641SAndroid Build Coastguard Worker+ // Chrome OS libchrome 181*635a8641SAndroid Build Coastguard Worker+ friend class base::FileDescriptorWatcher; 182*635a8641SAndroid Build Coastguard Worker+ 183*635a8641SAndroid Build Coastguard Worker // END ALLOWED USAGE. 184*635a8641SAndroid Build Coastguard Worker // BEGIN USAGE THAT NEEDS TO BE FIXED. 185*635a8641SAndroid Build Coastguard Worker friend class ::chromeos::BlockingMethodCaller; // http://crbug.com/125360 186*635a8641SAndroid Build Coastguard Worker-- 187*635a8641SAndroid Build Coastguard Worker2.24.1.735.g03f4e72817-goog 188*635a8641SAndroid Build Coastguard Worker 189