]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/builtins/os_version_check.c
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / builtins / os_version_check.c
1 /* ===-- os_version_check.c - OS version checking  -------------------------===
2  *
3  *                     The LLVM Compiler Infrastructure
4  *
5  * This file is dual licensed under the MIT and the University of Illinois Open
6  * Source Licenses. See LICENSE.TXT for details.
7  *
8  * ===----------------------------------------------------------------------===
9  *
10  * This file implements the function __isOSVersionAtLeast, used by
11  * Objective-C's @available
12  *
13  * ===----------------------------------------------------------------------===
14  */
15
16 #ifdef __APPLE__
17
18 #include <CoreFoundation/CoreFoundation.h>
19 #include <TargetConditionals.h>
20 #include <dispatch/dispatch.h>
21 #include <dlfcn.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 /* These three variables hold the host's OS version. */
28 static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
29 static dispatch_once_t DispatchOnceCounter;
30
31 typedef CFDataRef (*CFDataCreateWithBytesNoCopyFuncTy)(CFAllocatorRef,
32                                                        const UInt8 *, CFIndex,
33                                                        CFAllocatorRef);
34 typedef CFPropertyListRef (*CFPropertyListCreateWithDataFuncTy)(
35     CFAllocatorRef, CFDataRef, CFOptionFlags, CFPropertyListFormat *,
36     CFErrorRef *);
37 typedef CFPropertyListRef (*CFPropertyListCreateFromXMLDataFuncTy)(
38     CFAllocatorRef, CFDataRef, CFOptionFlags, CFStringRef *);
39 typedef CFStringRef (*CFStringCreateWithCStringNoCopyFuncTy)(CFAllocatorRef,
40                                                              const char *,
41                                                              CFStringEncoding,
42                                                              CFAllocatorRef);
43 typedef const void *(*CFDictionaryGetValueFuncTy)(CFDictionaryRef,
44                                                   const void *);
45 typedef CFTypeID (*CFGetTypeIDFuncTy)(CFTypeRef);
46 typedef CFTypeID (*CFStringGetTypeIDFuncTy)(void);
47 typedef Boolean (*CFStringGetCStringFuncTy)(CFStringRef, char *, CFIndex,
48                                             CFStringEncoding);
49 typedef void (*CFReleaseFuncTy)(CFTypeRef);
50
51 /* Find and parse the SystemVersion.plist file. */
52 static void parseSystemVersionPList(void *Unused) {
53   (void)Unused;
54   /* Load CoreFoundation dynamically */
55   const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
56   if (!NullAllocator)
57     return;
58   const CFAllocatorRef kCFAllocatorNull =
59       *(const CFAllocatorRef *)NullAllocator;
60   CFDataCreateWithBytesNoCopyFuncTy CFDataCreateWithBytesNoCopyFunc =
61       (CFDataCreateWithBytesNoCopyFuncTy)dlsym(RTLD_DEFAULT,
62                                                "CFDataCreateWithBytesNoCopy");
63   if (!CFDataCreateWithBytesNoCopyFunc)
64     return;
65   CFPropertyListCreateWithDataFuncTy CFPropertyListCreateWithDataFunc =
66       (CFPropertyListCreateWithDataFuncTy)dlsym(
67           RTLD_DEFAULT, "CFPropertyListCreateWithData");
68 /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
69  * will be NULL on earlier OS versions. */
70 #pragma clang diagnostic push
71 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
72   CFPropertyListCreateFromXMLDataFuncTy CFPropertyListCreateFromXMLDataFunc =
73       (CFPropertyListCreateFromXMLDataFuncTy)dlsym(
74           RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");
75 #pragma clang diagnostic pop
76   /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
77    * might be NULL in future OS versions. */
78   if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)
79     return;
80   CFStringCreateWithCStringNoCopyFuncTy CFStringCreateWithCStringNoCopyFunc =
81       (CFStringCreateWithCStringNoCopyFuncTy)dlsym(
82           RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy");
83   if (!CFStringCreateWithCStringNoCopyFunc)
84     return;
85   CFDictionaryGetValueFuncTy CFDictionaryGetValueFunc =
86       (CFDictionaryGetValueFuncTy)dlsym(RTLD_DEFAULT, "CFDictionaryGetValue");
87   if (!CFDictionaryGetValueFunc)
88     return;
89   CFGetTypeIDFuncTy CFGetTypeIDFunc =
90       (CFGetTypeIDFuncTy)dlsym(RTLD_DEFAULT, "CFGetTypeID");
91   if (!CFGetTypeIDFunc)
92     return;
93   CFStringGetTypeIDFuncTy CFStringGetTypeIDFunc =
94       (CFStringGetTypeIDFuncTy)dlsym(RTLD_DEFAULT, "CFStringGetTypeID");
95   if (!CFStringGetTypeIDFunc)
96     return;
97   CFStringGetCStringFuncTy CFStringGetCStringFunc =
98       (CFStringGetCStringFuncTy)dlsym(RTLD_DEFAULT, "CFStringGetCString");
99   if (!CFStringGetCStringFunc)
100     return;
101   CFReleaseFuncTy CFReleaseFunc =
102       (CFReleaseFuncTy)dlsym(RTLD_DEFAULT, "CFRelease");
103   if (!CFReleaseFunc)
104     return;
105
106   char *PListPath = "/System/Library/CoreServices/SystemVersion.plist";
107
108 #if TARGET_OS_SIMULATOR
109   char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT");
110   if (!PListPathPrefix)
111     return;
112   char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1];
113   strcpy(FullPath, PListPathPrefix);
114   strcat(FullPath, PListPath);
115   PListPath = FullPath;
116 #endif
117   FILE *PropertyList = fopen(PListPath, "r");
118   if (!PropertyList)
119     return;
120
121   /* Dynamically allocated stuff. */
122   CFDictionaryRef PListRef = NULL;
123   CFDataRef FileContentsRef = NULL;
124   UInt8 *PListBuf = NULL;
125
126   fseek(PropertyList, 0, SEEK_END);
127   long PListFileSize = ftell(PropertyList);
128   if (PListFileSize < 0)
129     goto Fail;
130   rewind(PropertyList);
131
132   PListBuf = malloc((size_t)PListFileSize);
133   if (!PListBuf)
134     goto Fail;
135
136   size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList);
137   if (NumRead != (size_t)PListFileSize)
138     goto Fail;
139
140   /* Get the file buffer into CF's format. We pass in a null allocator here *
141    * because we free PListBuf ourselves */
142   FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
143       NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull);
144   if (!FileContentsRef)
145     goto Fail;
146
147   if (CFPropertyListCreateWithDataFunc)
148     PListRef = (*CFPropertyListCreateWithDataFunc)(
149         NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL);
150   else
151     PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
152         NULL, FileContentsRef, kCFPropertyListImmutable, NULL);
153   if (!PListRef)
154     goto Fail;
155
156   CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
157       NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull);
158   if (!ProductVersion)
159     goto Fail;
160   CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
161   (*CFReleaseFunc)(ProductVersion);
162   if (!OpaqueValue ||
163       (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)())
164     goto Fail;
165
166   char VersionStr[32];
167   if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
168                                  sizeof(VersionStr), kCFStringEncodingUTF8))
169     goto Fail;
170   sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
171
172 Fail:
173   if (PListRef)
174     (*CFReleaseFunc)(PListRef);
175   if (FileContentsRef)
176     (*CFReleaseFunc)(FileContentsRef);
177   free(PListBuf);
178   fclose(PropertyList);
179 }
180
181 int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
182   /* Populate the global version variables, if they haven't already. */
183   dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
184
185   if (Major < GlobalMajor)
186     return 1;
187   if (Major > GlobalMajor)
188     return 0;
189   if (Minor < GlobalMinor)
190     return 1;
191   if (Minor > GlobalMinor)
192     return 0;
193   return Subminor <= GlobalSubminor;
194 }
195
196 #else
197
198 /* Silence an empty translation unit warning. */
199 typedef int unused;
200
201 #endif