xref: /aosp_15_r20/external/libchrome/libchrome_tools/patches/fix-fd-watcher-leak.patch (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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