diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp @@ -606,21 +606,65 @@ return result; } -// This corresponds to Triple::getMacOSXVersion() in the Clang driver. -static MacosVersion GetMacosAlignedVersionInternal() { - u16 kernel_major = GetDarwinKernelVersion().major; - // Darwin 0-3 -> unsupported - // Darwin 4-19 -> macOS 10.x - // Darwin 20+ -> macOS 11+ - CHECK_GE(kernel_major, 4); - u16 major, minor; - if (kernel_major < 20) { - major = 10; - minor = kernel_major - 4; +using VersStr = char[64]; + +static void GetOSVersion(VersStr vers) { + uptr len = sizeof(VersStr); + if (SANITIZER_IOSSIM) { + const char *vers_env = GetEnv("SIMULATOR_RUNTIME_VERSION"); + if (!vers_env) { + Report("ERROR: Running in simulator but SIMULATOR_RUNTIME_VERSION env " + "var is not set.\n"); + Die(); + } + len = internal_strlcpy(vers, vers_env, len); } else { - major = 11 + kernel_major - 20; - minor = 0; + int res = + internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0); + CHECK_EQ(res, 0); + } + CHECK_LT(len, sizeof(VersStr)); +} + +void ParseVersion(const char *vers, u16 *major, u16 *minor) { + // Format: .[.]\0 + CHECK_GE(internal_strlen(vers), 3); + const char *p = vers; + *major = internal_simple_strtoll(p, &p, /*base=*/10); + CHECK_EQ(*p, '.'); + p += 1; + *minor = internal_simple_strtoll(p, &p, /*base=*/10); +} + +// Aligned versions example: +// macOS 10.15 -- iOS 13 -- tvOS 13 -- watchOS 6 +static void MapToMacos(u16 *major, u16 *minor) { + if (TARGET_OS_OSX) + return; + + if (SANITIZER_IOS || SANITIZER_TVOS) + *major += 2; + else if (SANITIZER_WATCHOS) + *major += 9; + else + UNREACHABLE("unsupported platform"); + + if (*major >= 16) { // macOS 11+ + *major -= 5; + } else { // macOS 10.15 and below + *minor = *major; + *major = 10; } +} + +static MacosVersion GetMacosAlignedVersionInternal() { + VersStr vers; + GetOSVersion(vers); + + u16 major, minor; + ParseVersion(vers, &major, &minor); + MapToMacos(&major, &minor); + return MacosVersion(major, minor); } @@ -639,24 +683,15 @@ return *reinterpret_cast(&result); } -void ParseVersion(const char *vers, u16 *major, u16 *minor) { - // Format: ..\0 - CHECK_GE(internal_strlen(vers), 5); - const char *p = vers; - *major = internal_simple_strtoll(p, &p, /*base=*/10); - CHECK_EQ(*p, '.'); - p += 1; - *minor = internal_simple_strtoll(p, &p, /*base=*/10); -} - DarwinKernelVersion GetDarwinKernelVersion() { - char buf[100]; - size_t len = sizeof(buf); - int res = internal_sysctlbyname("kern.osrelease", buf, &len, nullptr, 0); + VersStr vers; + uptr len = sizeof(VersStr); + int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0); CHECK_EQ(res, 0); + CHECK_LT(len, sizeof(VersStr)); u16 major, minor; - ParseVersion(buf, &major, &minor); + ParseVersion(vers, &major, &minor); return DarwinKernelVersion(major, minor); } diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_mac_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_mac_test.cpp --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_mac_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_mac_test.cpp @@ -22,6 +22,38 @@ namespace __sanitizer { +void ParseVersion(const char *vers, u16 *major, u16 *minor); + +TEST(SanitizerMac, ParseVersion) { + u16 major, minor; + + ParseVersion("11.22.33", &major, &minor); + EXPECT_EQ(major, 11); + EXPECT_EQ(minor, 22); + + ParseVersion("1.2", &major, &minor); + EXPECT_EQ(major, 1); + EXPECT_EQ(minor, 2); +} + +// TODO(yln): Run sanitizer unit tests for the simulators (rdar://65680742) +#if SANITIZER_IOSSIM +TEST(SanitizerMac, GetMacosAlignedVersion) { + const char *vers_str; + if (SANITIZER_IOS || SANITIZER_TVOS) { + vers_str = "13.0"; + } else if (SANITIZER_WATCHOS) { + vers_str = "6.5"; + } else { + FAIL() << "unsupported simulator runtime"; + } + setenv("SIMULATOR_RUNTIME_VERSION", vers_str, /*overwrite=*/1); + + MacosVersion vers = GetMacosAlignedVersion(); + EXPECT_EQ(vers.major, 10); + EXPECT_EQ(vers.minor, 15); +} +#else TEST(SanitizerMac, GetMacosAlignedVersion) { MacosVersion vers = GetMacosAlignedVersion(); u16 kernel_major = GetDarwinKernelVersion().major; @@ -31,15 +63,7 @@ EXPECT_EQ(vers.major, expected_major); EXPECT_EQ(vers.minor, expected_minor); } - -void ParseVersion(const char *vers, u16 *major, u16 *minor); - -TEST(SanitizerMac, ParseVersion) { - u16 major, minor; - ParseVersion("11.22.33", &major, &minor); - EXPECT_EQ(major, 11); - EXPECT_EQ(minor, 22); -} +#endif TEST(SanitizerMac, GetDarwinKernelVersion) { DarwinKernelVersion vers = GetDarwinKernelVersion();