• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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