diff options
-rw-r--r-- | lib/builtins/os_version_check.c | 85 | ||||
-rw-r--r-- | test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c | 12 |
2 files changed, 80 insertions, 17 deletions
diff --git a/lib/builtins/os_version_check.c b/lib/builtins/os_version_check.c index b36ae546e..fd8a96ae2 100644 --- a/lib/builtins/os_version_check.c +++ b/lib/builtins/os_version_check.c @@ -18,6 +18,7 @@ #include <CoreFoundation/CoreFoundation.h> #include <dispatch/dispatch.h> #include <TargetConditionals.h> +#include <dlfcn.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -30,6 +31,55 @@ static dispatch_once_t DispatchOnceCounter; /* Find and parse the SystemVersion.plist file. */ static void parseSystemVersionPList(void *Unused) { (void)Unused; + /* Load CoreFoundation dynamically */ + const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull"); + if (!NullAllocator) + return; + const CFAllocatorRef kCFAllocatorNull = + *(const CFAllocatorRef *)NullAllocator; + typeof(CFDataCreateWithBytesNoCopy) *CFDataCreateWithBytesNoCopyFunc = + (typeof(CFDataCreateWithBytesNoCopy) *)dlsym( + RTLD_DEFAULT, "CFDataCreateWithBytesNoCopy"); + if (!CFDataCreateWithBytesNoCopyFunc) + return; + typeof(CFPropertyListCreateWithData) *CFPropertyListCreateWithDataFunc = + (typeof(CFPropertyListCreateWithData) *)dlsym( + RTLD_DEFAULT, "CFPropertyListCreateWithData"); + /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it + * will be NULL on earlier OS versions. */ + typeof(CFPropertyListCreateFromXMLData) *CFPropertyListCreateFromXMLDataFunc = + (typeof(CFPropertyListCreateFromXMLData) *)dlsym( + RTLD_DEFAULT, "CFPropertyListCreateFromXMLData"); + /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it + * might be NULL in future OS versions. */ + if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc) + return; + typeof(CFStringCreateWithCStringNoCopy) *CFStringCreateWithCStringNoCopyFunc = + (typeof(CFStringCreateWithCStringNoCopy) *)dlsym( + RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy"); + if (!CFStringCreateWithCStringNoCopyFunc) + return; + typeof(CFDictionaryGetValue) *CFDictionaryGetValueFunc = + (typeof(CFDictionaryGetValue) *)dlsym(RTLD_DEFAULT, + "CFDictionaryGetValue"); + if (!CFDictionaryGetValueFunc) + return; + typeof(CFGetTypeID) *CFGetTypeIDFunc = + (typeof(CFGetTypeID) *)dlsym(RTLD_DEFAULT, "CFGetTypeID"); + if (!CFGetTypeIDFunc) + return; + typeof(CFStringGetTypeID) *CFStringGetTypeIDFunc = + (typeof(CFStringGetTypeID) *)dlsym(RTLD_DEFAULT, "CFStringGetTypeID"); + if (!CFStringGetTypeIDFunc) + return; + typeof(CFStringGetCString) *CFStringGetCStringFunc = + (typeof(CFStringGetCString) *)dlsym(RTLD_DEFAULT, "CFStringGetCString"); + if (!CFStringGetCStringFunc) + return; + typeof(CFRelease) *CFReleaseFunc = + (typeof(CFRelease) *)dlsym(RTLD_DEFAULT, "CFRelease"); + if (!CFReleaseFunc) + return; char *PListPath = "/System/Library/CoreServices/SystemVersion.plist"; @@ -67,40 +117,41 @@ static void parseSystemVersionPList(void *Unused) { /* Get the file buffer into CF's format. We pass in a null allocator here * * because we free PListBuf ourselves */ - FileContentsRef = CFDataCreateWithBytesNoCopy( + FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)( NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull); if (!FileContentsRef) goto Fail; - if (&CFPropertyListCreateWithData) - PListRef = CFPropertyListCreateWithData( + if (CFPropertyListCreateWithDataFunc) + PListRef = (*CFPropertyListCreateWithDataFunc)( NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL); - else { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - PListRef = CFPropertyListCreateFromXMLData(NULL, FileContentsRef, - kCFPropertyListImmutable, NULL); -#pragma clang diagnostic pop - } + else + PListRef = (*CFPropertyListCreateFromXMLDataFunc)( + NULL, FileContentsRef, kCFPropertyListImmutable, NULL); if (!PListRef) goto Fail; - CFTypeRef OpaqueValue = - CFDictionaryGetValue(PListRef, CFSTR("ProductVersion")); - if (!OpaqueValue || CFGetTypeID(OpaqueValue) != CFStringGetTypeID()) + CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)( + NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull); + if (!ProductVersion) + goto Fail; + CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion); + (*CFReleaseFunc)(ProductVersion); + if (!OpaqueValue || + (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)()) goto Fail; char VersionStr[32]; - if (!CFStringGetCString((CFStringRef)OpaqueValue, VersionStr, - sizeof(VersionStr), kCFStringEncodingUTF8)) + if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr, + sizeof(VersionStr), kCFStringEncodingUTF8)) goto Fail; sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor); Fail: if (PListRef) - CFRelease(PListRef); + (*CFReleaseFunc)(PListRef); if (FileContentsRef) - CFRelease(FileContentsRef); + (*CFReleaseFunc)(FileContentsRef); free(PListBuf); fclose(PropertyList); } diff --git a/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c b/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c new file mode 100644 index 000000000..4e0da35cd --- /dev/null +++ b/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c @@ -0,0 +1,12 @@ +// RUN: %clang %s -o %t -mmacosx-version-min=10.5 +// RUN: %run %t + +int __isOSVersionAtLeast(int Major, int Minor, int Subminor); + +int main() { + // When CoreFoundation isn't linked, we expect the system version to be 0, 0, + // 0. + if (__isOSVersionAtLeast(1, 0, 0)) + return 1; + return 0; +} |