Skip to content

Commit d708415

Browse files
committed
Initialize _allBundles in _CFBundleCopyAllBundles before trying to copy it.
The array `_allBundles` is lazily created when the first item is inserted into it in the `_CFBundleAddToTablesLocked` function. There’s a possibility that by the time `_CFBundleCopyAllBundles` is called, `_allBundles` hasn’t been initialized yet. In such cases, lazily initialize `_allBundles`. resolves: rdar://150846072
1 parent 94ef6ab commit d708415

File tree

2 files changed

+23
-11
lines changed

2 files changed

+23
-11
lines changed

Sources/CoreFoundation/CFBundle.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -255,22 +255,26 @@ CF_PRIVATE CFURLRef _CFURLCreateResolvedDirectoryWithString(CFAllocatorRef alloc
255255
#pragma mark -
256256
#pragma mark Bundle Tables
257257

258+
static void __CFBundleCreateAllBundlesArrayLocked() {
259+
CFArrayCallBacks callbacks = kCFTypeArrayCallBacks;
260+
#if TARGET_OS_OSX
261+
if (_useUnsafeUnretainedTables()) {
262+
callbacks.retain = NULL;
263+
callbacks.release = NULL;
264+
}
265+
#endif
266+
// The _allBundles array holds a strong reference on the bundle.
267+
// It does this to prevent a race on bundle deallocation / creation. See: <rdar://problem/6606482> CFBundle isn't thread-safe in RR mode
268+
// Also, the existence of the CFBundleGetBundleWithIdentifier / CFBundleGetAllBundles API means that any bundle we hand out from there must be permanently retained, or callers will potentially have an object that can be deallocated out from underneath them.
269+
_allBundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &callbacks);
270+
}
271+
258272
static void _CFBundleAddToTablesLocked(CFBundleRef bundle, CFStringRef bundleID) {
259273
if (bundle->_isUnique) return;
260274

261275
// Add to the _allBundles list
262276
if (!_allBundles) {
263-
CFArrayCallBacks callbacks = kCFTypeArrayCallBacks;
264-
#if TARGET_OS_OSX
265-
if (_useUnsafeUnretainedTables()) {
266-
callbacks.retain = NULL;
267-
callbacks.release = NULL;
268-
}
269-
#endif
270-
// The _allBundles array holds a strong reference on the bundle.
271-
// It does this to prevent a race on bundle deallocation / creation. See: <rdar://problem/6606482> CFBundle isn't thread-safe in RR mode
272-
// Also, the existence of the CFBundleGetBundleWithIdentifier / CFBundleGetAllBundles API means that any bundle we hand out from there must be permanently retained, or callers will potentially have an object that can be deallocated out from underneath them.
273-
_allBundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &callbacks);
277+
__CFBundleCreateAllBundlesArrayLocked();
274278
}
275279
CFArrayAppendValue(_allBundles, bundle);
276280

@@ -1795,6 +1799,11 @@ CF_EXPORT CFArrayRef _CFBundleCopyAllBundles(void) {
17951799
_CFBundleEnsureAllBundlesUpToDate();
17961800
CFBundleRef main = CFBundleGetMainBundle();
17971801
_CFMutexLock(&CFBundleGlobalDataLock);
1802+
// There is a chance that `_allBundles` haven't been initiated
1803+
// if no one called `CFBundleCreate()` yet
1804+
if (!_allBundles) {
1805+
__CFBundleCreateAllBundlesArrayLocked();
1806+
}
17981807
// _allBundles does not include the main bundle, so insert it here.
17991808
CFMutableArrayRef bundles = CFArrayCreateMutableCopy(kCFAllocatorSystemDefault, CFArrayGetCount(_allBundles) + 1, _allBundles);
18001809
_CFMutexUnlock(&CFBundleGlobalDataLock);

Sources/CoreFoundation/CFRuntime.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,6 +1810,9 @@ CF_CROSS_PLATFORM_EXPORT void _CFDeinit(CFTypeRef cf) {
18101810
}
18111811

18121812
bool _CFIsSwift(CFTypeID type, CFSwiftRef obj) {
1813+
if (obj == NULL) {
1814+
return false;
1815+
}
18131816
if (type == _kCFRuntimeNotATypeID) {
18141817
return false;
18151818
}

0 commit comments

Comments
 (0)