1// Copyright 2012 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "partition_alloc/partition_alloc_base/mac/mac_util.h" 6 7#include <stddef.h> 8#include <string.h> 9#include <sys/sysctl.h> 10#include <sys/types.h> 11#include <sys/utsname.h> 12 13#include "partition_alloc/partition_alloc_base/check.h" 14#include "partition_alloc/partition_alloc_base/logging.h" 15 16// This is a simplified version of base::mac. Because 17// "base/strings/string_split.h" is unavailable, only provide access to the 18// macOS major version number via direct string work on the Darwin version. 19 20namespace partition_alloc::internal::base::mac { 21 22namespace { 23 24// Returns the running system's Darwin major version. Don't call this, it's an 25// implementation detail and its result is meant to be cached by 26// MacOSMajorVersion(). 27int DarwinMajorVersion() { 28 // base::OperatingSystemVersionNumbers() at one time called Gestalt(), which 29 // was observed to be able to spawn threads (see https://crbug.com/53200). 30 // Nowadays that function calls -[NSProcessInfo operatingSystemVersion], whose 31 // current implementation does things like hit the file system, which is 32 // possibly a blocking operation. Either way, it's overkill for what needs to 33 // be done here. 34 // 35 // uname, on the other hand, is implemented as a simple series of sysctl 36 // system calls to obtain the relevant data from the kernel. The data is 37 // compiled right into the kernel, so no threads or blocking or other 38 // funny business is necessary. 39 40 struct utsname uname_info; 41 if (uname(&uname_info) != 0) { 42 PA_DPLOG(ERROR) << "uname"; 43 return 0; 44 } 45 46 if (strcmp(uname_info.sysname, "Darwin") != 0) { 47 PA_DLOG(ERROR) << "unexpected uname sysname " << uname_info.sysname; 48 return 0; 49 } 50 51 const char* dot = strchr(uname_info.release, '.'); 52 if (!dot || uname_info.release == dot || 53 // Darwin version should be 1 or 2 digits, it's unlikely to be more than 54 // 4 digits. 55 dot - uname_info.release > 4) { 56 PA_DLOG(ERROR) << "could not parse uname release " << uname_info.release; 57 return 0; 58 } 59 60 int darwin_major_version = 0; 61 constexpr int base = 10; 62 for (const char* p = uname_info.release; p < dot; ++p) { 63 if (!('0' <= *p && *p < '0' + base)) { 64 PA_DLOG(ERROR) << "could not parse uname release " << uname_info.release; 65 return 0; 66 } 67 68 // Since we checked the number of digits is 4 at most (see above), there is 69 // no chance to overflow. 70 darwin_major_version *= base; 71 darwin_major_version += *p - '0'; 72 } 73 74 return darwin_major_version; 75} 76 77} // namespace 78 79int MacOSMajorVersion() { 80 static int macos_major_version = [] { 81 int darwin_major_version = DarwinMajorVersion(); 82 83 // Darwin major versions 6 through 19 corresponded to macOS versions 10.2 84 // through 10.15. 85 PA_BASE_CHECK(darwin_major_version >= 6); 86 if (darwin_major_version <= 19) { 87 return 10; 88 } 89 90 // Darwin major version 20 corresponds to macOS version 11.0. Assume a 91 // correspondence between Darwin's major version numbers and macOS major 92 // version numbers. 93 return darwin_major_version - 9; 94 }(); 95 return macos_major_version; 96} 97 98} // namespace partition_alloc::internal::base::mac 99