88#include " platform/utils.h"
99#include " platform/utils_macos.h"
1010
11- #include < errno.h> // NOLINT
1211#include < sys/utsname.h> // NOLINT
1312
1413namespace dart {
@@ -81,91 +80,114 @@ int Utils::Unlink(const char* path) {
8180
8281namespace internal {
8382
84- // Returns the running system's Darwin major version. Don't call this, it's
85- // an implementation detail and its result is meant to be cached by
86- // MacOSXMinorVersion.
87- int32_t DarwinMajorVersionInternal ( ) {
83+ namespace {
84+ // Extracts the version of the running kernel from utsname.release.
85+ bool GetDarwinKernelVersionFromUname ( int32_t * kernel_major_version,
86+ int32_t * kernel_minor_version ) {
8887 // uname is implemented as a simple series of sysctl system calls to
8988 // obtain the relevant data from the kernel. The data is
9089 // compiled right into the kernel, so no threads or blocking or other
9190 // funny business is necessary.
9291
9392 struct utsname uname_info;
9493 if (uname (&uname_info) != 0 ) {
95- FATAL (" Fatal error in DarwinMajorVersionInternal : invalid return uname" );
96- return 0 ;
94+ FATAL (" GetDarwinKernelVersionFromUname: uname failed " );
95+ return false ;
9796 }
9897
9998 if (strcmp (uname_info.sysname , " Darwin" ) != 0 ) {
10099 FATAL (
101- " Fatal error in DarwinMajorVersionInternal : unexpected uname"
100+ " GetDarwinKernelVersionFromUname : unexpected uname"
102101 " sysname '%s'" ,
103102 uname_info.sysname );
104- return 0 ;
103+ return false ;
105104 }
106105
107- int32_t darwin_major_version = 0 ;
106+ *kernel_major_version = 0 ;
107+ *kernel_minor_version = 0 ;
108108 char * dot = strchr (uname_info.release , ' .' );
109- if (dot) {
110- errno = 0 ;
109+ if (dot != nullptr && dot != uname_info.release ) {
111110 char * end_ptr = nullptr ;
112- darwin_major_version = strtol (uname_info.release , &end_ptr, 10 );
113- if (errno != 0 || (end_ptr == uname_info.release )) {
114- dot = nullptr ;
111+ *kernel_major_version = strtol (uname_info.release , &end_ptr, 10 );
112+ if (end_ptr == dot) { // Expected to parse until `.`
113+ char * minor_start = dot + 1 ;
114+ *kernel_minor_version = strtol (minor_start, &end_ptr, 10 );
115+ if (end_ptr != minor_start) {
116+ return true ;
117+ }
115118 }
116119 }
117120
118- if (!dot) {
119- FATAL (
120- " Fatal error in DarwinMajorVersionInternal :"
121- " could not parse uname release '%s'" ,
122- uname_info.release );
123- return 0 ;
124- }
125-
126- return darwin_major_version;
121+ FATAL (
122+ " GetDarwinKernelVersionFromUname: "
123+ " could not parse uname release '%s'" ,
124+ uname_info.release );
125+ return false ;
127126}
128127
129- // Returns the running system's Mac OS X version which matches the encoding
130- // of MAC_OS_X_VERSION_* defines in AvailabilityMacros.h
131- int32_t MacOSXVersionInternal () {
132- const int32_t darwin_major_version = DarwinMajorVersionInternal ();
128+ } // namespace
133129
134- int32_t major_version;
135- int32_t minor_version;
130+ // Returns the running system's Mac OS X or iOS version which matches the
131+ // encoding of *_X_VERSION_* defines in AvailabilityVersions.h
132+ int32_t DarwinVersionInternal () {
133+ int32_t kernel_major_version;
134+ int32_t kernel_minor_version;
135+ if (!GetDarwinKernelVersionFromUname (&kernel_major_version,
136+ &kernel_minor_version)) {
137+ return 0 ;
138+ }
136139
137- if (darwin_major_version < 20 ) {
140+ int32_t major_version = 0 ;
141+ int32_t minor_version = 0 ;
142+
143+ #if defined(DART_HOST_OS_IOS)
144+ // We do not expect to run on version of iOS <12.0 so we can assume that
145+ // kernel version is off by 6 from iOS version (e.g. kernel 18.0 is iOS 12.0).
146+ // This only holds starting from iOS 4.0.
147+ major_version = kernel_major_version - 6 ;
148+ if (major_version >= 15 ) {
149+ // After iOS 15 minor version of kernel is the same as minor version of
150+ // the iOS release. Before iOS 15 these numbers were not in sync. However
151+ // We do not expect to check minor version numbers for older iOS
152+ // releases so we just keep it at 0 for them.
153+ minor_version = kernel_minor_version;
154+ }
155+ const int32_t field_multiplier = 100 ;
156+ #else
157+ if (kernel_major_version < 20 ) {
138158 // For Mac OS X 10.* minor version is off by 4 from Darwin's major
139159 // version, e.g. 5.* is v10.1.*, 6.* is v10.2.* and so on.
140160 // Pretend that anything below Darwin v5 is just Mac OS X Cheetah (v10.0).
141161 major_version = 10 ;
142- minor_version = Utils::Maximum (0 , darwin_major_version - 4 );
162+ minor_version = Utils::Maximum (0 , kernel_major_version - 4 );
143163 } else {
144164 // Starting from Darwin v20 major version increment in lock-step:
145165 // Darwin v20 - Mac OS X v11, Darwin v21 - Mac OS X v12, etc
146- major_version = (darwin_major_version - 9 );
166+ major_version = (kernel_major_version - 9 );
147167 minor_version = 0 ;
148168 }
149169
150170 // Caveat: MAC_OS_X_VERSION_* is encoded using decimal encoding.
151171 // Starting at MAC_OS_X_VERSION_10_10 versions use 2 decimal digits for
152172 // minor version and patch number.
153- const int32_t field_multiplier = (darwin_major_version < 14 ) ? 10 : 100 ;
173+ const int32_t field_multiplier = (kernel_major_version < 14 ) ? 10 : 100 ;
174+ #endif
154175 const int32_t major_multiplier = field_multiplier * field_multiplier;
155176 const int32_t minor_multiplier = field_multiplier;
156177
157178 return major_version * major_multiplier + minor_version * minor_multiplier;
158179}
159180
160- int32_t MacOSXVersion () {
161- static int mac_os_x_version = MacOSXVersionInternal ();
162- return mac_os_x_version ;
181+ int32_t DarwinVersion () {
182+ static int version = DarwinVersionInternal ();
183+ return version ;
163184}
164185
165186} // namespace internal
166187
188+ #if !defined(DART_HOST_OS_IOS)
167189namespace {
168- int32_t MacOSMinorVersion (int32_t version) {
190+ int32_t MacOSXMinorVersion (int32_t version) {
169191 // Caveat: MAC_OS_X_VERSION_* is encoded using decimal encoding.
170192 // Starting at MAC_OS_X_VERSION_10_10 versions use 2 decimal digits for
171193 // minor version and patch number.
@@ -174,7 +196,7 @@ int32_t MacOSMinorVersion(int32_t version) {
174196 return (version / field_multiplier) % field_multiplier;
175197}
176198
177- int32_t MacOSMajorVersion (int32_t version) {
199+ int32_t MacOSXMajorVersion (int32_t version) {
178200 // Caveat: MAC_OS_X_VERSION_* is encoded using decimal encoding.
179201 // Starting at MAC_OS_X_VERSION_10_10 versions use 2 decimal digits for
180202 // minor version and patch number.
@@ -184,8 +206,8 @@ int32_t MacOSMajorVersion(int32_t version) {
184206}
185207} // namespace
186208
187- char * CheckIsAtLeastMinRequiredMacOSVersion () {
188- const int32_t current_version = internal::MacOSXVersion ();
209+ char * CheckIsAtLeastMinRequiredMacOSXVersion () {
210+ const int32_t current_version = internal::DarwinVersion ();
189211
190212 if (current_version >= MAC_OS_X_VERSION_MIN_REQUIRED) {
191213 return nullptr ;
@@ -194,10 +216,11 @@ char* CheckIsAtLeastMinRequiredMacOSVersion() {
194216 return Utils::SCreate (
195217 " Current Mac OS X version %d.%d is lower than minimum supported version "
196218 " %d.%d" ,
197- MacOSMajorVersion (current_version), MacOSMinorVersion (current_version),
198- MacOSMajorVersion (MAC_OS_X_VERSION_MIN_REQUIRED),
199- MacOSMinorVersion (MAC_OS_X_VERSION_MIN_REQUIRED));
219+ MacOSXMajorVersion (current_version), MacOSXMinorVersion (current_version),
220+ MacOSXMajorVersion (MAC_OS_X_VERSION_MIN_REQUIRED),
221+ MacOSXMinorVersion (MAC_OS_X_VERSION_MIN_REQUIRED));
200222}
223+ #endif
201224
202225} // namespace dart
203226
0 commit comments