This is an archive of the discontinued LLVM Phabricator instance.

[Darwin] Improve runtime OS version checks
ClosedPublic

Authored by yln on May 14 2020, 3:04 PM.

Details

Summary

Use a struct to represent numerical versions instead of encoding release
names in an enumeration. This avoids the need to extend the enumeration
every time there is a new release.

Rename GetMacosVersion() -> GetMacosAlignedVersion() to better reflect
how this is used on non-MacOS platforms.

Diff Detail

Event Timeline

yln created this revision.May 14 2020, 3:04 PM
Herald added a project: Restricted Project. · View Herald Transcript
Herald added subscribers: Restricted Project, jfb. · View Herald Transcript
delcypher accepted this revision.May 20 2020, 6:30 PM

LGTM, minus the problems in previous patches.

This revision is now accepted and ready to land.May 20 2020, 6:30 PM
delcypher requested changes to this revision.May 30 2020, 3:06 PM

Looks good apart from the missing check for underflow. This patch is of course broken for the simulators but it was before this patch and I know in future patches that you plan to fix this.

compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
610–615

Maybe should have a check to make sure we don't perform unsigned underflow..

Maybe something like this?

auto kernel_version = GetDarwinKernelVersion();
const u16 version_offset = 4;
CHECK_GE(kernel_version.major, version_offset);
return MacosVersion(10, kernel_verson.major - version_offset);
This revision now requires changes to proceed.May 30 2020, 3:06 PM
yln updated this revision to Diff 267669.Jun 1 2020, 10:48 AM

Add version underflow check.

yln marked an inline comment as done.Jun 1 2020, 10:49 AM
delcypher requested changes to this revision.Jun 1 2020, 12:44 PM

LGTM other than the use of uint32_t.

compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
618–628

This should probably be u32 (sanitizer internal) rather than uint32_t which comes from a C library header.

Similarly in GetMacosAlignedVersion() too.

This revision now requires changes to proceed.Jun 1 2020, 12:44 PM
yln updated this revision to Diff 267729.Jun 1 2020, 2:15 PM

Use atomic_uint32_t::Type instead of uint32_t.

yln marked an inline comment as done.Jun 1 2020, 2:20 PM
delcypher accepted this revision.Jun 3 2020, 11:49 AM

I have an optional suggestion to improve this patch. Other than that LGTM.

compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
630

Suggestion: I'm not a big fan of all the reinterpret_cast<>s which assume there's no alignment padding in the MacosVersion struct. One way around this is to add methods to MacosVersion that allow for serializing/deserializing from a u32.

template <typename VersionType>
struct VersionBase {
  // ...
  static VersionBase<VersionType> FromU32(u32 repr) {
     u16 major =  repr & 0xff;
     u16 minor = (repr >> 16) & 0xff;
     return VersionBase<VersionType>(major, minor);
  }

  u32 ToU32() {
    u32 repr = static_cast<u32>(major) + (static_cast<u32>(minor) >> 16);
    CHECK_EQ(VersionBase<VersionType>::FromU32(repr), *this);
    return repr;
  }
};

then you can have

MacosVersion GetMacosAlignedVersion() {
  atomic_uint32_t::Type result =
      atomic_load(&cached_macos_version, memory_order_acquire);
  if (!result) {
    MacosVersion version = GetMacosAlignedVersionInternal();
    result = version::ToU32();
    atomic_store(&cached_macos_version, result, memory_order_release);
  }
  return MacosVersion::FromU32(result);
}

However, you have a nice static_assert which will catch if this assumption about alignment breaks so I guess this is okay. So please consider the above a non-blocking suggestion. If you like it you can adopt it but feel free to land this patch as it is.

This revision is now accepted and ready to land.Jun 3 2020, 11:49 AM
yln marked an inline comment as done.Jun 3 2020, 12:17 PM
yln added inline comments.
compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp
630

Yes, I feel that reinterpret_cast is always a wart. I will consider a follow-up (since it was already there in the old code). Best would be std::atomic<MacosVersion> but we can’t since its compiler-rt…

What do you think about removing the caching altogether? I am pretty sure it’s a case of premature optimization: I looked at all the call sites and none of them is in a loop; the function is used in initialization, or when printing an error/walking the stack. One use is in the setjmp/longjmp interceptor.

Another option would be to remove the atomic part from the caching. 1) It’s first queried during initialization, which is single-threaded and even if we would race (due to code changes) in the future; the query really should always return the same result.

This revision was automatically updated to reflect the committed changes.