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