Skip to content

Commit 79f69b2

Browse files
committed
Fix race in index delegate callback
All calls to `processingCompleted` are called from the unit processing queue, but `processingAddedPending` can be called from other queues, including an arbitrary queue in the case of `addUnitOutFilePaths` and `removeUnitOutFilePaths`. The result is that if there is a session being processed, we might increment and decrement `PendingActions` concurrently. We obsevered an assertion failure where `NumActions` was greater than `NumActions`, which was likely caused by this race. rdar://68024910
1 parent 4a4085d commit 79f69b2

File tree

1 file changed

+19
-28
lines changed

1 file changed

+19
-28
lines changed

lib/Index/IndexSystem.cpp

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ class AsyncIndexDelegate : public IndexSystemDelegate {
5050
AsyncIndexDelegate(std::shared_ptr<IndexSystemDelegate> Other)
5151
: Others(1, std::move(Other)) {}
5252

53+
~AsyncIndexDelegate() {
54+
_wait(); // Ensure the queue is drained, since we capture `this`.
55+
}
56+
5357
void addDelegate(std::shared_ptr<IndexSystemDelegate> Other) {
5458
Queue.dispatchSync([&] {
5559
if (PendingActions)
@@ -60,36 +64,25 @@ class AsyncIndexDelegate : public IndexSystemDelegate {
6064

6165
private:
6266
virtual void processingAddedPending(unsigned NumActions) override {
63-
PendingActions += NumActions;
64-
65-
if (Others.empty())
66-
return;
67-
auto LocalOthers = this->Others;
68-
Queue.dispatch([LocalOthers, NumActions]{
69-
for (auto &other : LocalOthers)
67+
Queue.dispatch([this, NumActions]{
68+
PendingActions += NumActions;
69+
for (auto &other : Others)
7070
other->processingAddedPending(NumActions);
7171
});
7272
}
7373

7474
virtual void processingCompleted(unsigned NumActions) override {
75-
assert(NumActions <= PendingActions);
76-
PendingActions -= NumActions;
77-
78-
if (Others.empty())
79-
return;
80-
auto LocalOthers = this->Others;
81-
Queue.dispatch([LocalOthers, NumActions]{
82-
for (auto &other : LocalOthers)
75+
Queue.dispatch([this, NumActions]{
76+
assert(NumActions <= PendingActions);
77+
PendingActions -= NumActions;
78+
for (auto &other : Others)
8379
other->processingCompleted(NumActions);
8480
});
8581
}
8682

8783
virtual void processedStoreUnit(StoreUnitInfo unitInfo) override {
88-
if (Others.empty())
89-
return;
90-
auto LocalOthers = this->Others;
91-
Queue.dispatch([LocalOthers, unitInfo]{
92-
for (auto &other : LocalOthers)
84+
Queue.dispatch([this, unitInfo]{
85+
for (auto &other : Others)
9386
other->processedStoreUnit(unitInfo);
9487
});
9588
}
@@ -98,24 +91,22 @@ class AsyncIndexDelegate : public IndexSystemDelegate {
9891
llvm::sys::TimePoint<> outOfDateModTime,
9992
OutOfDateTriggerHintRef hint,
10093
bool synchronous) override {
101-
if (Others.empty())
102-
return;
103-
10494
if (synchronous) {
105-
for (auto &other : Others)
106-
other->unitIsOutOfDate(std::move(unitInfo), outOfDateModTime, hint, true);
95+
Queue.dispatchSync([&]{
96+
for (auto &other : Others)
97+
other->unitIsOutOfDate(std::move(unitInfo), outOfDateModTime, hint, true);
98+
});
10799
return;
108100
}
109101

110-
auto LocalOthers = this->Others;
111102
Queue.dispatch([=]{
112-
for (auto &other : LocalOthers)
103+
for (auto &other : Others)
113104
other->unitIsOutOfDate(std::move(unitInfo), outOfDateModTime, hint, false);
114105
});
115106
}
116107

117108
public:
118-
/// For Testing. Wait for any outstanding async work to finish.
109+
/// Public for Testing. Wait for any outstanding async work to finish.
119110
void _wait() {
120111
Queue.dispatchSync([]{});
121112
}

0 commit comments

Comments
 (0)