1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/mach/mach_extensions.h"
16
17 #include "base/mac/scoped_mach_port.h"
18 #include "gtest/gtest.h"
19 #include "test/mac/mach_errors.h"
20 #include "util/mac/mac_util.h"
21 #include "util/misc/random_string.h"
22
23 namespace crashpad {
24 namespace test {
25 namespace {
26
TEST(MachExtensions,MachThreadSelf)27 TEST(MachExtensions, MachThreadSelf) {
28 base::mac::ScopedMachSendRight thread_self(mach_thread_self());
29 EXPECT_EQ(MachThreadSelf(), thread_self);
30 }
31
TEST(MachExtensions,NewMachPort_Receive)32 TEST(MachExtensions, NewMachPort_Receive) {
33 base::mac::ScopedMachReceiveRight port(NewMachPort(MACH_PORT_RIGHT_RECEIVE));
34 ASSERT_NE(port, kMachPortNull);
35
36 mach_port_type_t type;
37 kern_return_t kr = mach_port_type(mach_task_self(), port.get(), &type);
38 ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "mach_port_get_type");
39
40 EXPECT_EQ(type, MACH_PORT_TYPE_RECEIVE);
41 }
42
TEST(MachExtensions,NewMachPort_PortSet)43 TEST(MachExtensions, NewMachPort_PortSet) {
44 base::mac::ScopedMachPortSet port(NewMachPort(MACH_PORT_RIGHT_PORT_SET));
45 ASSERT_NE(port, kMachPortNull);
46
47 mach_port_type_t type;
48 kern_return_t kr = mach_port_type(mach_task_self(), port.get(), &type);
49 ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "mach_port_get_type");
50
51 EXPECT_EQ(type, MACH_PORT_TYPE_PORT_SET);
52 }
53
TEST(MachExtensions,NewMachPort_DeadName)54 TEST(MachExtensions, NewMachPort_DeadName) {
55 base::mac::ScopedMachSendRight port(NewMachPort(MACH_PORT_RIGHT_DEAD_NAME));
56 ASSERT_NE(port, kMachPortNull);
57
58 mach_port_type_t type;
59 kern_return_t kr = mach_port_type(mach_task_self(), port.get(), &type);
60 ASSERT_EQ(kr, KERN_SUCCESS) << MachErrorMessage(kr, "mach_port_get_type");
61
62 EXPECT_EQ(type, MACH_PORT_TYPE_DEAD_NAME);
63 }
64
65 constexpr exception_mask_t kExcMaskBasic =
66 EXC_MASK_BAD_ACCESS |
67 EXC_MASK_BAD_INSTRUCTION |
68 EXC_MASK_ARITHMETIC |
69 EXC_MASK_EMULATION |
70 EXC_MASK_SOFTWARE |
71 EXC_MASK_BREAKPOINT |
72 EXC_MASK_SYSCALL |
73 EXC_MASK_MACH_SYSCALL |
74 EXC_MASK_RPC_ALERT;
75
TEST(MachExtensions,ExcMaskAll)76 TEST(MachExtensions, ExcMaskAll) {
77 const exception_mask_t exc_mask_all = ExcMaskAll();
78 EXPECT_EQ(exc_mask_all & kExcMaskBasic, kExcMaskBasic);
79
80 EXPECT_FALSE(exc_mask_all & EXC_MASK_CRASH);
81 EXPECT_FALSE(exc_mask_all & EXC_MASK_CORPSE_NOTIFY);
82
83 const int mac_os_x_minor_version = MacOSXMinorVersion();
84 if (mac_os_x_minor_version >= 8) {
85 EXPECT_TRUE(exc_mask_all & EXC_MASK_RESOURCE);
86 } else {
87 EXPECT_FALSE(exc_mask_all & EXC_MASK_RESOURCE);
88 }
89
90 if (mac_os_x_minor_version >= 9) {
91 EXPECT_TRUE(exc_mask_all & EXC_MASK_GUARD);
92 } else {
93 EXPECT_FALSE(exc_mask_all & EXC_MASK_GUARD);
94 }
95
96 // Bit 0 should not be set.
97 EXPECT_FALSE(ExcMaskAll() & 1);
98
99 // Every bit set in ExcMaskAll() must also be set in ExcMaskValid().
100 EXPECT_EQ(ExcMaskAll() & ExcMaskValid(), ExcMaskAll());
101 }
102
TEST(MachExtensions,ExcMaskValid)103 TEST(MachExtensions, ExcMaskValid) {
104 const exception_mask_t exc_mask_valid = ExcMaskValid();
105 EXPECT_EQ(exc_mask_valid & kExcMaskBasic, kExcMaskBasic);
106
107 EXPECT_TRUE(exc_mask_valid & EXC_MASK_CRASH);
108
109 const int mac_os_x_minor_version = MacOSXMinorVersion();
110 if (mac_os_x_minor_version >= 8) {
111 EXPECT_TRUE(exc_mask_valid & EXC_MASK_RESOURCE);
112 } else {
113 EXPECT_FALSE(exc_mask_valid & EXC_MASK_RESOURCE);
114 }
115
116 if (mac_os_x_minor_version >= 9) {
117 EXPECT_TRUE(exc_mask_valid & EXC_MASK_GUARD);
118 } else {
119 EXPECT_FALSE(exc_mask_valid & EXC_MASK_GUARD);
120 }
121
122 if (mac_os_x_minor_version >= 11) {
123 EXPECT_TRUE(exc_mask_valid & EXC_MASK_CORPSE_NOTIFY);
124 } else {
125 EXPECT_FALSE(exc_mask_valid & EXC_MASK_CORPSE_NOTIFY);
126 }
127
128 // Bit 0 should not be set.
129 EXPECT_FALSE(ExcMaskValid() & 1);
130
131 // There must be bits set in ExcMaskValid() that are not set in ExcMaskAll().
132 EXPECT_TRUE(ExcMaskValid() & ~ExcMaskAll());
133 }
134
TEST(MachExtensions,BootstrapCheckInAndLookUp)135 TEST(MachExtensions, BootstrapCheckInAndLookUp) {
136 // This should always exist.
137 base::mac::ScopedMachSendRight
138 report_crash(BootstrapLookUp("com.apple.ReportCrash"));
139 EXPECT_NE(report_crash, kMachPortNull);
140
141 std::string service_name = "org.chromium.crashpad.test.bootstrap_check_in.";
142 service_name.append(RandomString());
143
144 {
145 // The new service hasn’t checked in yet, so this should fail.
146 base::mac::ScopedMachSendRight send(BootstrapLookUp(service_name));
147 EXPECT_EQ(send, kMachPortNull);
148
149 // Check it in.
150 base::mac::ScopedMachReceiveRight receive(BootstrapCheckIn(service_name));
151 EXPECT_NE(receive, kMachPortNull);
152
153 // Now it should be possible to look up the new service.
154 send = BootstrapLookUp(service_name);
155 EXPECT_NE(send, kMachPortNull);
156
157 // It shouldn’t be possible to check the service in while it’s active.
158 base::mac::ScopedMachReceiveRight receive_2(BootstrapCheckIn(service_name));
159 EXPECT_EQ(receive_2, kMachPortNull);
160 }
161
162 // The new service should be gone now.
163 base::mac::ScopedMachSendRight send(BootstrapLookUp(service_name));
164 EXPECT_EQ(send, kMachPortNull);
165
166 // It should be possible to check it in again.
167 base::mac::ScopedMachReceiveRight receive(BootstrapCheckIn(service_name));
168 EXPECT_NE(receive, kMachPortNull);
169 }
170
TEST(MachExtensions,SystemCrashReporterHandler)171 TEST(MachExtensions, SystemCrashReporterHandler) {
172 base::mac::ScopedMachSendRight
173 system_crash_reporter_handler(SystemCrashReporterHandler());
174 EXPECT_TRUE(system_crash_reporter_handler.is_valid());
175 }
176
177 } // namespace
178 } // namespace test
179 } // namespace crashpad
180