mac: Update the process_types version of dyld_all_image_infos for 10.15

macOS 10.15 (“Catalina”) introduces a single new field to its
dyld_all_image_infos structure, and uses structure version 16.

macOS 10.13 and 10.14 were documented in <mach-o/dyld_images.h> as using
structure version 16, but they actually use version 15. They should have
used version 16, as they do use a structure expanded from macOS 10.12,
which also uses version 15. Previously, process_types was true to the
documentation, but now that this is known to be incorrect, it’s been
revised to reflect reality. Because two variants of the version 15
structure exist, run-time OS version detection is used to disambiguate.

Bug: crashpad:310
Test: crashpad_snapshot_test ProcessTypes.DyldImagesSelf (10.15 SDK)
Change-Id: Ibc82b6a73809949f4bbf416ece7aa955b627c573
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1852109
Commit-Queue: Mark Mentovai <mark@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
Mark Mentovai 2019-10-10 17:34:12 -04:00 committed by Commit Bot
parent fe52a01df1
commit 2fb4e9e6a4
4 changed files with 116 additions and 23 deletions

View File

@ -59,4 +59,16 @@
#define MAC_OS_X_VERSION_10_13 101300
#endif
// 10.14 SDK
#ifndef MAC_OS_X_VERSION_10_14
#define MAC_OS_X_VERSION_10_14 101400
#endif
// 10.15 SDK
#ifndef MAC_OS_X_VERSION_10_15
#define MAC_OS_X_VERSION_10_15 101500
#endif
#endif // CRASHPAD_COMPAT_MAC_AVAILABILITYMACROS_H_

View File

@ -19,6 +19,7 @@
#include <sys/types.h>
#include <algorithm>
#include <limits>
#include <type_traits>
#include "base/logging.h"
@ -26,6 +27,7 @@
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "snapshot/mac/process_types/internal.h"
#include "util/mac/mac_util.h"
#include "util/process/process_memory_mac.h"
#if !DOXYGEN
@ -140,8 +142,8 @@ size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion(
offsetof(dyld_all_image_infos<Traits>, sharedCacheSlide), // 11
offsetof(dyld_all_image_infos<Traits>, sharedCacheUUID), // 12
offsetof(dyld_all_image_infos<Traits>, infoArrayChangeTimestamp), // 13
offsetof(dyld_all_image_infos<Traits>, end_14_15), // 14
offsetof(dyld_all_image_infos<Traits>, end_14_15), // 15
offsetof(dyld_all_image_infos<Traits>, end_14), // 14
std::numeric_limits<size_t>::max(), // 15, see below
sizeof(dyld_all_image_infos<Traits>), // 16
};
@ -151,7 +153,27 @@ size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion(
static_assert(std::is_unsigned<decltype(version)>::value,
"version must be unsigned");
return kSizeForVersion[version];
if (version == 15) {
// Disambiguate between the two different layouts for version 15. The
// original one introduced in macOS 10.12 had the same size as version 14.
// The revised one in macOS 10.13 grew. Its safe to assume that the
// dyld_all_image_infos structure came from the same system thats now
// interpreting it, so use an OS version check.
int mac_os_x_minor_version = MacOSXMinorVersion();
if (mac_os_x_minor_version == 12) {
return offsetof(dyld_all_image_infos<Traits>, end_14);
}
DCHECK_GE(mac_os_x_minor_version, 13);
DCHECK_LE(mac_os_x_minor_version, 14);
return offsetof(dyld_all_image_infos<Traits>, platform);
}
size_t size = kSizeForVersion[version];
DCHECK_NE(size, std::numeric_limits<size_t>::max());
return size;
}
// static

View File

@ -121,23 +121,29 @@ PROCESS_TYPE_STRUCT_BEGIN(dyld_all_image_infos)
// the runtimes that use versions 14 and 15 were built with SDKs that did not
// have this extra padding, its necessary to treat the element at index 4 on
// 32-bit systems as outside of the version 14 and 15 structure. This is why
// |reserved| is only declared a 4-element array, with a special end_14_15
// member (not present in the native definition) available to indicate the
// end of the native version 14 and 15 structure, preceding the padding in the
// 32-bit structure that would natively be addressed at index 4 of |reserved|.
// Treat reserved_4_32 as only available in version 16 of the structure.
// |reserved| is only declared a 4-element array, with a special end_14 member
// (not present in the native definition) available to indicate the end of the
// native version 14 structure and the 10.12 version 15 structure, preceding
// the padding in the 32-bit structure that would natively be addressed at
// index 4 of |reserved|. Treat reserved_4_32 as only available in version 16
// of the structure.
PROCESS_TYPE_STRUCT_MEMBER(UIntPtr, reserved, [4])
PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_4_64)
PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_5)
PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_6)
PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_7)
PROCESS_TYPE_STRUCT_MEMBER(Reserved64_64Only, reserved_8)
PROCESS_TYPE_STRUCT_MEMBER(Nothing, end_14_15)
PROCESS_TYPE_STRUCT_MEMBER(Nothing, end_14)
PROCESS_TYPE_STRUCT_MEMBER(Reserved32_32Only, reserved_4_32)
// Version 16 (macOS 10.13)
// Version 15 (macOS 10.13). <mach-o/dyld_images.h> incorrectly claims that
// these were introduced at version 16. These fields are not present in macOS
// 10.12, which also identifies its structure as version 15.
PROCESS_TYPE_STRUCT_MEMBER(UIntPtr, compact_dyld_image_info_addr)
PROCESS_TYPE_STRUCT_MEMBER(ULong, compact_dyld_image_info_size) // size_t
// Version 16 (macOS 10.15)
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, platform) // dyld_platform_t
PROCESS_TYPE_STRUCT_END(dyld_all_image_infos)
#endif // ! PROCESS_TYPE_STRUCT_IMPLEMENT_INTERNAL_READ_INTO &&

View File

@ -18,6 +18,7 @@
#include <mach/mach.h>
#include <string.h>
#include <limits>
#include <vector>
#include "base/stl_util.h"
@ -47,13 +48,11 @@ namespace {
TEST(ProcessTypes, DyldImagesSelf) {
// Get the in-process view of dyld_all_image_infos, and check it for sanity.
const dyld_all_image_infos* self_image_infos = DyldGetAllImageInfos();
int mac_os_x_minor_version = MacOSXMinorVersion();
const int mac_os_x_minor_version = MacOSXMinorVersion();
// The 10.13 SDK defines dyld_all_image_infos version 16 and says that its
// used on 10.13, but 10.13db1 17A264c uses version 15.
//
// TODO(mark): Recheck later in the beta period, up to the 10.13 release.
if (mac_os_x_minor_version >= 12) {
if (mac_os_x_minor_version >= 15) {
EXPECT_GE(self_image_infos->version, 16u);
} else if (mac_os_x_minor_version >= 12) {
EXPECT_GE(self_image_infos->version, 15u);
} else if (mac_os_x_minor_version >= 9) {
EXPECT_GE(self_image_infos->version, 13u);
@ -104,7 +103,7 @@ TEST(ProcessTypes, DyldImagesSelf) {
ProcessReaderMac process_reader;
ASSERT_TRUE(process_reader.Initialize(mach_task_self()));
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15
constexpr uint32_t kDyldAllImageInfosVersionInSDK = 16;
#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
constexpr uint32_t kDyldAllImageInfosVersionInSDK = 15;
@ -120,12 +119,33 @@ TEST(ProcessTypes, DyldImagesSelf) {
// Make sure that the size of the structure as declared in the SDK matches the
// size expected for the version of the structure that the SDK describes.
EXPECT_EQ(process_types::dyld_all_image_infos::ExpectedSizeForVersion(
&process_reader, kDyldAllImageInfosVersionInSDK),
sizeof(dyld_all_image_infos));
//
// There are two possible layouts for version 15, and the
// ExpectedSizeForVersion() implementation infers the correct one based on the
// run-time OS version, so if the SDK defines the version 15 structure, this
// test can only be performed if the run-time OS natively uses the same format
// structure as the SDK.
bool test_expected_size_for_version_matches_sdk_sizeof;
#if MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_12
test_expected_size_for_version_matches_sdk_sizeof =
mac_os_x_minor_version == 12;
#elif MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 && \
MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_14
test_expected_size_for_version_matches_sdk_sizeof =
mac_os_x_minor_version >= 13 && mac_os_x_minor_version <= 14;
#else
test_expected_size_for_version_matches_sdk_sizeof = true;
#endif
if (test_expected_size_for_version_matches_sdk_sizeof) {
EXPECT_EQ(process_types::dyld_all_image_infos::ExpectedSizeForVersion(
&process_reader, kDyldAllImageInfosVersionInSDK),
sizeof(dyld_all_image_infos));
}
// Make sure that the computed sizes of various versions of this structure are
// correct at different bitnessses.
constexpr size_t kSpecialCase = std::numeric_limits<size_t>::max();
constexpr struct {
uint32_t version;
size_t size_32;
@ -144,13 +164,40 @@ TEST(ProcessTypes, DyldImagesSelf) {
{12, 84, 160},
{13, 104, 184},
{14, 164, 304},
{15, 164, 304},
{16, 176, 320},
{15, kSpecialCase, kSpecialCase},
{16, 184, 328},
};
for (size_t index = 0; index < base::size(kVersionsAndSizes); ++index) {
uint32_t version = kVersionsAndSizes[index].version;
SCOPED_TRACE(base::StringPrintf("index %zu, version %u", index, version));
if (version == 15) {
if (mac_os_x_minor_version == 12) {
EXPECT_EQ(process_types::internal::dyld_all_image_infos<
process_types::internal::Traits32>::
ExpectedSizeForVersion(version),
164u);
EXPECT_EQ(process_types::internal::dyld_all_image_infos<
process_types::internal::Traits64>::
ExpectedSizeForVersion(version),
304u);
} else if (mac_os_x_minor_version >= 13 && mac_os_x_minor_version <= 14) {
EXPECT_EQ(process_types::internal::dyld_all_image_infos<
process_types::internal::Traits32>::
ExpectedSizeForVersion(version),
176u);
EXPECT_EQ(process_types::internal::dyld_all_image_infos<
process_types::internal::Traits64>::
ExpectedSizeForVersion(version),
320u);
}
continue;
}
ASSERT_NE(kVersionsAndSizes[index].size_32, kSpecialCase);
ASSERT_NE(kVersionsAndSizes[index].size_64, kSpecialCase);
EXPECT_EQ(
process_types::internal::dyld_all_image_infos<
process_types::internal::Traits32>::ExpectedSizeForVersion(version),
@ -306,7 +353,7 @@ TEST(ProcessTypes, DyldImagesSelf) {
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
if (proctype_image_infos.version >= 16) {
if (proctype_image_infos.version >= 15 && mac_os_x_minor_version >= 13) {
EXPECT_EQ(proctype_image_infos.compact_dyld_image_info_addr,
self_image_infos->compact_dyld_image_info_addr);
EXPECT_EQ(proctype_image_infos.compact_dyld_image_info_size,
@ -314,6 +361,12 @@ TEST(ProcessTypes, DyldImagesSelf) {
}
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_15
if (proctype_image_infos.version >= 16) {
EXPECT_EQ(proctype_image_infos.platform, self_image_infos->platform);
}
#endif
if (proctype_image_infos.version >= 1) {
std::vector<process_types::dyld_image_info> proctype_image_info_vector(
proctype_image_infos.infoArrayCount);