Skip to content

Commit 20219b9

Browse files
authored
Merge pull request #10665 from nextcloud/work/launch-crash-fp
fix(file-provider): Prevent concurrent write crash in XPC utils
2 parents a3dd597 + 573a035 commit 20219b9

3 files changed

Lines changed: 95 additions & 0 deletions

File tree

src/gui/macOS/fileproviderxpc_mac_utils.mm

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,13 @@
7676
qCWarning(lcFileProviderXPCUtils) << "Failed to resolve service for file provider domain: " << error;
7777
} else if (service == nil) {
7878
qCWarning(lcFileProviderXPCUtils) << "Service is nil!";
79+
} else if (service.name == nil) {
80+
qCWarning(lcFileProviderXPCUtils) << "Service has no name";
7981
} else {
82+
@synchronized (fpServices) {
8083
[fpServices addObject:@{service.name: service}];
8184
}
85+
}
8286

8387
dispatch_group_leave(group);
8488
}];
@@ -106,7 +110,11 @@
106110
}
107111

108112
qCDebug(lcFileProviderXPCUtils) << "Got user visible url" << url;
113+
if (url != nil) {
114+
@synchronized (urls) {
109115
[urls addObject:url];
116+
}
117+
}
110118
dispatch_group_leave(group);
111119
}];
112120
}
@@ -140,7 +148,11 @@
140148
<< url.absoluteString
141149
<< "has number of services:"
142150
<< services.count;
151+
if (services != nil) {
152+
@synchronized (fpServices) {
143153
[fpServices addObject:services];
154+
}
155+
}
144156
dispatch_group_leave(group);
145157
}];
146158
}
@@ -187,7 +199,9 @@
187199
return;
188200
}
189201

202+
@synchronized (connections) {
190203
[connections addObject:connection];
204+
}
191205
dispatch_group_leave(group);
192206
}];
193207
}

test/macOS/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@
77
nextcloud_add_test(FinderSyncBrokerIdentity)
88
nextcloud_add_test(SystraySyncControlMacOS)
99
nextcloud_add_test(MacSandboxUtility)
10+
11+
if(BUILD_FILE_PROVIDER_MODULE)
12+
nextcloud_add_test(FileProviderXPCUtils)
13+
set_source_files_properties(testfileproviderxpcutils.cpp PROPERTIES COMPILE_FLAGS "-x objective-c++")
14+
endif()
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: GPL-2.0-or-later
4+
*/
5+
6+
#include <QtTest>
7+
8+
#include "macOS/fileproviderxpc_mac_utils.h"
9+
10+
#import <FileProvider/FileProvider.h>
11+
12+
@interface TestFileProviderService : NSObject
13+
@property (nonatomic, copy) NSString *name;
14+
@end
15+
16+
@implementation TestFileProviderService
17+
@end
18+
19+
@interface TestFileProviderManager : NSObject
20+
@property (nonatomic, retain) NSFileProviderService *service;
21+
@end
22+
23+
@implementation TestFileProviderManager
24+
25+
- (void)getServiceWithName:(NSFileProviderServiceName)serviceName
26+
itemIdentifier:(NSFileProviderItemIdentifier)itemIdentifier
27+
completionHandler:(void (^)(NSFileProviderService *service, NSError *error))completionHandler
28+
{
29+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
30+
completionHandler(self.service, nil);
31+
});
32+
}
33+
34+
@end
35+
36+
class TestFileProviderXPCUtils : public QObject
37+
{
38+
Q_OBJECT
39+
40+
private Q_SLOTS:
41+
void concurrentServiceLookupsCanBeCollected()
42+
{
43+
constexpr auto managerCount = 128;
44+
NSMutableArray<NSFileProviderManager *> * const managers = NSMutableArray.array;
45+
46+
for (auto index = 0; index < managerCount; ++index) {
47+
const auto service = [TestFileProviderService new];
48+
service.name = [NSString stringWithFormat:@"service-%d", index];
49+
50+
const auto manager = [TestFileProviderManager new];
51+
manager.service = (NSFileProviderService *)service;
52+
[managers addObject:(NSFileProviderManager *)manager];
53+
[service release];
54+
[manager release];
55+
}
56+
57+
const auto services = OCC::Mac::FileProviderXPCUtils::getFileProviderServices(managers);
58+
QCOMPARE(services.count, managerCount);
59+
}
60+
61+
void serviceWithoutNameIsIgnored()
62+
{
63+
const auto service = [TestFileProviderService new];
64+
const auto manager = [TestFileProviderManager new];
65+
manager.service = (NSFileProviderService *)service;
66+
67+
const auto services = OCC::Mac::FileProviderXPCUtils::getFileProviderServices(@[(NSFileProviderManager *)manager]);
68+
QCOMPARE(services.count, 0);
69+
70+
[service release];
71+
[manager release];
72+
}
73+
};
74+
75+
QTEST_APPLESS_MAIN(TestFileProviderXPCUtils)
76+
#include "testfileproviderxpcutils.moc"

0 commit comments

Comments
 (0)