Ticket #57694: ken_os_version_check_clang-6.c

File ken_os_version_check_clang-6.c, 7.3 KB (added by kencu (Ken), 5 years ago)

my patched version of os_version_check.c with a small test prog added on the bottom

Line 
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 <AvailabilityMacros.h>
19#include <CoreFoundation/CoreFoundation.h>
20#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
21 #include <dispatch/dispatch.h>
22#endif
23#include <TargetConditionals.h>
24#include <dlfcn.h>
25#include <stdint.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30/* These three variables hold the host's OS version. */
31static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
32#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
33 static dispatch_once_t DispatchOnceCounter;
34#endif
35
36#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
37/* declare a missing reference not found in SDK < 10.6 for function called below */
38typedef struct __CFError * CFErrorRef;
39extern CFPropertyListRef CFPropertyListCreateWithData(CFAllocatorRef, CFDataRef, CFOptionFlags, CFPropertyListFormat *, CFErrorRef *);
40#endif
41
42/* Find and parse the SystemVersion.plist file. */
43static void parseSystemVersionPList(void *Unused) {
44  (void)Unused;
45  /* Load CoreFoundation dynamically */
46  const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
47  if (!NullAllocator)
48    return;
49  const CFAllocatorRef kCFAllocatorNull =
50      *(const CFAllocatorRef *)NullAllocator;
51  typeof(CFDataCreateWithBytesNoCopy) *CFDataCreateWithBytesNoCopyFunc =
52      (typeof(CFDataCreateWithBytesNoCopy) *)dlsym(
53          RTLD_DEFAULT, "CFDataCreateWithBytesNoCopy");
54  if (!CFDataCreateWithBytesNoCopyFunc)
55    return;
56  typeof(CFPropertyListCreateWithData) *CFPropertyListCreateWithDataFunc =
57      (typeof(CFPropertyListCreateWithData) *)dlsym(
58          RTLD_DEFAULT, "CFPropertyListCreateWithData");
59  /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
60   * will be NULL on earlier OS versions. */
61#pragma clang diagnostic push
62#pragma clang diagnostic ignored "-Wdeprecated-declarations"
63  typeof(CFPropertyListCreateFromXMLData) *CFPropertyListCreateFromXMLDataFunc =
64      (typeof(CFPropertyListCreateFromXMLData) *)dlsym(
65          RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");
66#pragma clang diagnostic pop
67  /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
68   * might be NULL in future OS versions. */
69  if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)
70    return;
71  typeof(CFStringCreateWithCStringNoCopy) *CFStringCreateWithCStringNoCopyFunc =
72      (typeof(CFStringCreateWithCStringNoCopy) *)dlsym(
73          RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy");
74  if (!CFStringCreateWithCStringNoCopyFunc)
75    return;
76  typeof(CFDictionaryGetValue) *CFDictionaryGetValueFunc =
77      (typeof(CFDictionaryGetValue) *)dlsym(RTLD_DEFAULT,
78                                            "CFDictionaryGetValue");
79  if (!CFDictionaryGetValueFunc)
80    return;
81  typeof(CFGetTypeID) *CFGetTypeIDFunc =
82      (typeof(CFGetTypeID) *)dlsym(RTLD_DEFAULT, "CFGetTypeID");
83  if (!CFGetTypeIDFunc)
84    return;
85  typeof(CFStringGetTypeID) *CFStringGetTypeIDFunc =
86      (typeof(CFStringGetTypeID) *)dlsym(RTLD_DEFAULT, "CFStringGetTypeID");
87  if (!CFStringGetTypeIDFunc)
88    return;
89  typeof(CFStringGetCString) *CFStringGetCStringFunc =
90      (typeof(CFStringGetCString) *)dlsym(RTLD_DEFAULT, "CFStringGetCString");
91  if (!CFStringGetCStringFunc)
92    return;
93  typeof(CFRelease) *CFReleaseFunc =
94      (typeof(CFRelease) *)dlsym(RTLD_DEFAULT, "CFRelease");
95  if (!CFReleaseFunc)
96    return;
97
98  char *PListPath = "/System/Library/CoreServices/SystemVersion.plist";
99
100#if TARGET_OS_SIMULATOR
101  char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT");
102  if (!PListPathPrefix)
103    return;
104  char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1];
105  strcpy(FullPath, PListPathPrefix);
106  strcat(FullPath, PListPath);
107  PListPath = FullPath;
108#endif
109  FILE *PropertyList = fopen(PListPath, "r");
110  if (!PropertyList)
111    return;
112
113  /* Dynamically allocated stuff. */
114  CFDictionaryRef PListRef = NULL;
115  CFDataRef FileContentsRef = NULL;
116  UInt8 *PListBuf = NULL;
117
118  fseek(PropertyList, 0, SEEK_END);
119  long PListFileSize = ftell(PropertyList);
120  if (PListFileSize < 0)
121    goto Fail;
122  rewind(PropertyList);
123
124  PListBuf = malloc((size_t)PListFileSize);
125  if (!PListBuf)
126    goto Fail;
127
128  size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList);
129  if (NumRead != (size_t)PListFileSize)
130    goto Fail;
131
132  /* Get the file buffer into CF's format. We pass in a null allocator here *
133   * because we free PListBuf ourselves */
134  FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
135      NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull);
136  if (!FileContentsRef)
137    goto Fail;
138
139  if (CFPropertyListCreateWithDataFunc)
140    PListRef = (*CFPropertyListCreateWithDataFunc)(
141        NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL);
142  else
143    PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
144        NULL, FileContentsRef, kCFPropertyListImmutable, NULL);
145  if (!PListRef)
146    goto Fail;
147
148  CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
149      NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull);
150  if (!ProductVersion)
151    goto Fail;
152  CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
153  (*CFReleaseFunc)(ProductVersion);
154  if (!OpaqueValue ||
155      (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)())
156    goto Fail;
157
158  char VersionStr[32];
159  if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
160                                 sizeof(VersionStr), kCFStringEncodingUTF8))
161    goto Fail;
162  sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
163
164Fail:
165  if (PListRef)
166    (*CFReleaseFunc)(PListRef);
167  if (FileContentsRef)
168    (*CFReleaseFunc)(FileContentsRef);
169  free(PListBuf);
170  fclose(PropertyList);
171}
172
173int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
174  /* Populate the global version variables, if they haven't already. */
175#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
176  dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
177#else
178  /* expensive procedure, only do once. GlobalMajor will not be 0 once run. */
179  if (GlobalMajor == 0) 
180    parseSystemVersionPList(NULL);
181#endif
182  if (Major < GlobalMajor) return 1;
183  if (Major > GlobalMajor) return 0;
184  if (Minor < GlobalMinor) return 1;
185  if (Minor > GlobalMinor) return 0;
186  return Subminor <= GlobalSubminor;
187}
188
189#else
190
191/* Silence an empty translation unit warning. */
192typedef int unused;
193
194#endif
195
196// Ken's Mini Test
197int main(void) {
198  int32_t test;
199  int32_t maj, min, sub;
200 
201  maj=10; sub=8;
202  for (min=4; min < 10; min++) {
203    for (sub=0; sub < 10; sub++) {
204          printf("Testing Major %d, Minor %d, SubMinor %d\n", maj, min, sub);
205         
206           test = __isOSVersionAtLeast(maj,min,sub);
207       
208          printf("GlobalMajor %d, GlobalMinor %d, GlobalSubminor %d\n", GlobalMajor,
209                         GlobalMinor, GlobalSubminor);
210       
211           if (test > 0) {
212                 printf("We're the same or newer! %d \n\n", test);
213                 }
214           if (test == 0) {
215                 printf("We're too old... %d \n\n", test);
216                 }
217     }
218   }
219
220return 0;
221}