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/exc_server_variants.h"
16
17 #include <mach/mach.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <sys/types.h>
21
22 #include "base/stl_util.h"
23 #include "base/strings/stringprintf.h"
24 #include "build/build_config.h"
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 #include "test/mac/mach_errors.h"
28 #include "util/mac/mac_util.h"
29 #include "util/mach/exception_behaviors.h"
30 #include "util/mach/exception_types.h"
31 #include "util/mach/mach_message.h"
32 #include "util/misc/implicit_cast.h"
33
34 #if defined(OS_MAC)
35 #include "test/mac/mach_multiprocess.h"
36 #endif // OS_MAC
37
38 namespace crashpad {
39 namespace test {
40 namespace {
41
42 using testing::DefaultValue;
43 using testing::Eq;
44 using testing::Pointee;
45 using testing::Return;
46
47 // Fake Mach ports. These aren’t used as ports in these tests, they’re just used
48 // as cookies to make sure that the correct values get passed to the correct
49 // places.
50 constexpr mach_port_t kClientRemotePort = 0x01010101;
51 constexpr mach_port_t kServerLocalPort = 0x02020202;
52 constexpr thread_t kExceptionThreadPort = 0x03030303;
53 constexpr task_t kExceptionTaskPort = 0x04040404;
54
55 // Other fake exception values.
56 constexpr exception_type_t kExceptionType = EXC_BAD_ACCESS;
57
58 // Test using an exception code with the high bit set to ensure that it gets
59 // promoted to the wider mach_exception_data_type_t type as a signed quantity.
60 constexpr exception_data_type_t kTestExceptonCodes[] = {
61 KERN_PROTECTION_FAILURE,
62 implicit_cast<exception_data_type_t>(0xfedcba98),
63 };
64
65 constexpr mach_exception_data_type_t kTestMachExceptionCodes[] = {
66 KERN_PROTECTION_FAILURE,
67 implicit_cast<mach_exception_data_type_t>(0xfedcba9876543210),
68 };
69
70 constexpr thread_state_flavor_t kThreadStateFlavor = MACHINE_THREAD_STATE;
71 constexpr mach_msg_type_number_t kThreadStateFlavorCount =
72 MACHINE_THREAD_STATE_COUNT;
73
InitializeMachMsgPortDescriptor(mach_msg_port_descriptor_t * descriptor,mach_port_t port)74 void InitializeMachMsgPortDescriptor(mach_msg_port_descriptor_t* descriptor,
75 mach_port_t port) {
76 descriptor->name = port;
77 descriptor->disposition = MACH_MSG_TYPE_PORT_SEND;
78 descriptor->type = MACH_MSG_PORT_DESCRIPTOR;
79 }
80
81 // The definitions of the request and reply structures from mach_exc.h aren’t
82 // available here. They need custom initialization code, and the reply
83 // structures need verification code too, so duplicate the expected definitions
84 // of the structures from both exc.h and mach_exc.h here in this file, and
85 // provide the initialization and verification code as methods in true
86 // object-oriented fashion.
87
88 struct __attribute__((packed, aligned(4))) ExceptionRaiseRequest {
ExceptionRaiseRequestcrashpad::test::__anon4206dd0d0111::ExceptionRaiseRequest89 ExceptionRaiseRequest() {
90 memset(this, 0xa5, sizeof(*this));
91 Head.msgh_bits =
92 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND) |
93 MACH_MSGH_BITS_COMPLEX;
94 Head.msgh_size = sizeof(*this) - sizeof(trailer);
95 Head.msgh_remote_port = kClientRemotePort;
96 Head.msgh_local_port = kServerLocalPort;
97 Head.msgh_id = 2401;
98 msgh_body.msgh_descriptor_count = 2;
99 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort);
100 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort);
101 NDR = NDR_record;
102 exception = kExceptionType;
103 codeCnt = 2;
104 code[0] = kTestExceptonCodes[0];
105 code[1] = kTestExceptonCodes[1];
106 }
107
108 mach_msg_header_t Head;
109 mach_msg_body_t msgh_body;
110 mach_msg_port_descriptor_t thread;
111 mach_msg_port_descriptor_t task;
112 NDR_record_t NDR;
113 exception_type_t exception;
114 mach_msg_type_number_t codeCnt;
115 integer_t code[2];
116 mach_msg_trailer_t trailer;
117 };
118
119 struct __attribute__((packed, aligned(4))) ExceptionRaiseReply {
ExceptionRaiseReplycrashpad::test::__anon4206dd0d0111::ExceptionRaiseReply120 ExceptionRaiseReply() {
121 memset(this, 0x5a, sizeof(*this));
122 RetCode = KERN_FAILURE;
123 }
124
125 // Verify accepts a |behavior| parameter because the same message format and
126 // verification function is used for ExceptionRaiseReply and
127 // MachExceptionRaiseReply. Knowing which behavior is expected allows the
128 // message ID to be checked.
Verifycrashpad::test::__anon4206dd0d0111::ExceptionRaiseReply129 void Verify(exception_behavior_t behavior) {
130 EXPECT_EQ(Head.msgh_bits,
131 implicit_cast<mach_msg_bits_t>(
132 MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0)));
133 EXPECT_EQ(Head.msgh_size, sizeof(*this));
134 EXPECT_EQ(Head.msgh_remote_port, kClientRemotePort);
135 EXPECT_EQ(Head.msgh_local_port, kMachPortNull);
136 switch (behavior) {
137 case EXCEPTION_DEFAULT:
138 EXPECT_EQ(Head.msgh_id, 2501);
139 break;
140 case EXCEPTION_DEFAULT | kMachExceptionCodes:
141 EXPECT_EQ(Head.msgh_id, 2505);
142 break;
143 default:
144 ADD_FAILURE() << "behavior " << behavior << ", Head.msgh_id "
145 << Head.msgh_id;
146 break;
147 }
148 EXPECT_EQ(memcmp(&NDR, &NDR_record, sizeof(NDR)), 0);
149 EXPECT_EQ(RetCode, KERN_SUCCESS);
150 }
151
152 mach_msg_header_t Head;
153 NDR_record_t NDR;
154 kern_return_t RetCode;
155 };
156
157 struct __attribute__((packed, aligned(4))) ExceptionRaiseStateRequest {
ExceptionRaiseStateRequestcrashpad::test::__anon4206dd0d0111::ExceptionRaiseStateRequest158 ExceptionRaiseStateRequest() {
159 memset(this, 0xa5, sizeof(*this));
160 Head.msgh_bits =
161 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND);
162 Head.msgh_size = sizeof(*this) - sizeof(trailer);
163 Head.msgh_remote_port = kClientRemotePort;
164 Head.msgh_local_port = kServerLocalPort;
165 Head.msgh_id = 2402;
166 NDR = NDR_record;
167 exception = kExceptionType;
168 codeCnt = 2;
169 code[0] = kTestExceptonCodes[0];
170 code[1] = kTestExceptonCodes[1];
171 flavor = kThreadStateFlavor;
172 old_stateCnt = kThreadStateFlavorCount;
173
174 // Adjust the message size for the data that it’s actually carrying, which
175 // may be smaller than the maximum that it can carry.
176 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state);
177 }
178
179 // Because the message size has been adjusted, the trailer may not appear in
180 // its home member variable. This computes the actual address of the trailer.
Trailercrashpad::test::__anon4206dd0d0111::ExceptionRaiseStateRequest181 const mach_msg_trailer_t* Trailer() const {
182 return MachMessageTrailerFromHeader(&Head);
183 }
184
185 mach_msg_header_t Head;
186 NDR_record_t NDR;
187 exception_type_t exception;
188 mach_msg_type_number_t codeCnt;
189 integer_t code[2];
190 int flavor;
191 mach_msg_type_number_t old_stateCnt;
192 natural_t old_state[THREAD_STATE_MAX];
193 mach_msg_trailer_t trailer;
194 };
195
196 struct __attribute__((packed, aligned(4))) ExceptionRaiseStateReply {
ExceptionRaiseStateReplycrashpad::test::__anon4206dd0d0111::ExceptionRaiseStateReply197 ExceptionRaiseStateReply() {
198 memset(this, 0x5a, sizeof(*this));
199 RetCode = KERN_FAILURE;
200 }
201
202 // Verify accepts a |behavior| parameter because the same message format and
203 // verification function is used for ExceptionRaiseStateReply,
204 // ExceptionRaiseStateIdentityReply, MachExceptionRaiseStateReply, and
205 // MachExceptionRaiseStateIdentityReply. Knowing which behavior is expected
206 // allows the message ID to be checked.
Verifycrashpad::test::__anon4206dd0d0111::ExceptionRaiseStateReply207 void Verify(exception_behavior_t behavior) {
208 EXPECT_EQ(Head.msgh_bits,
209 implicit_cast<mach_msg_bits_t>(
210 MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0)));
211 EXPECT_EQ(Head.msgh_size, sizeof(*this));
212 EXPECT_EQ(Head.msgh_remote_port, kClientRemotePort);
213 EXPECT_EQ(Head.msgh_local_port, kMachPortNull);
214 switch (behavior) {
215 case EXCEPTION_STATE:
216 EXPECT_EQ(Head.msgh_id, 2502);
217 break;
218 case EXCEPTION_STATE_IDENTITY:
219 EXPECT_EQ(Head.msgh_id, 2503);
220 break;
221 case EXCEPTION_STATE | kMachExceptionCodes:
222 EXPECT_EQ(Head.msgh_id, 2506);
223 break;
224 case EXCEPTION_STATE_IDENTITY | kMachExceptionCodes:
225 EXPECT_EQ(Head.msgh_id, 2507);
226 break;
227 default:
228 ADD_FAILURE() << "behavior " << behavior << ", Head.msgh_id "
229 << Head.msgh_id;
230 break;
231 }
232 EXPECT_EQ(memcmp(&NDR, &NDR_record, sizeof(NDR)), 0);
233 EXPECT_EQ(RetCode, KERN_SUCCESS);
234 EXPECT_EQ(flavor, kThreadStateFlavor);
235 EXPECT_EQ(new_stateCnt, base::size(new_state));
236 }
237
238 mach_msg_header_t Head;
239 NDR_record_t NDR;
240 kern_return_t RetCode;
241 int flavor;
242 mach_msg_type_number_t new_stateCnt;
243 natural_t new_state[THREAD_STATE_MAX];
244 };
245
246 struct __attribute__((packed, aligned(4))) ExceptionRaiseStateIdentityRequest {
ExceptionRaiseStateIdentityRequestcrashpad::test::__anon4206dd0d0111::ExceptionRaiseStateIdentityRequest247 ExceptionRaiseStateIdentityRequest() {
248 memset(this, 0xa5, sizeof(*this));
249 Head.msgh_bits =
250 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND) |
251 MACH_MSGH_BITS_COMPLEX;
252 Head.msgh_size = sizeof(*this) - sizeof(trailer);
253 Head.msgh_remote_port = kClientRemotePort;
254 Head.msgh_local_port = kServerLocalPort;
255 Head.msgh_id = 2403;
256 msgh_body.msgh_descriptor_count = 2;
257 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort);
258 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort);
259 NDR = NDR_record;
260 exception = kExceptionType;
261 codeCnt = 2;
262 code[0] = kTestExceptonCodes[0];
263 code[1] = kTestExceptonCodes[1];
264 flavor = kThreadStateFlavor;
265 old_stateCnt = kThreadStateFlavorCount;
266
267 // Adjust the message size for the data that it’s actually carrying, which
268 // may be smaller than the maximum that it can carry.
269 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state);
270 }
271
272 // Because the message size has been adjusted, the trailer may not appear in
273 // its home member variable. This computes the actual address of the trailer.
Trailercrashpad::test::__anon4206dd0d0111::ExceptionRaiseStateIdentityRequest274 const mach_msg_trailer_t* Trailer() const {
275 return MachMessageTrailerFromHeader(&Head);
276 }
277
278 mach_msg_header_t Head;
279 mach_msg_body_t msgh_body;
280 mach_msg_port_descriptor_t thread;
281 mach_msg_port_descriptor_t task;
282 NDR_record_t NDR;
283 exception_type_t exception;
284 mach_msg_type_number_t codeCnt;
285 integer_t code[2];
286 int flavor;
287 mach_msg_type_number_t old_stateCnt;
288 natural_t old_state[THREAD_STATE_MAX];
289 mach_msg_trailer_t trailer;
290 };
291
292 // The reply messages for exception_raise_state and
293 // exception_raise_state_identity are identical.
294 using ExceptionRaiseStateIdentityReply = ExceptionRaiseStateReply;
295
296 struct __attribute__((packed, aligned(4))) MachExceptionRaiseRequest {
MachExceptionRaiseRequestcrashpad::test::__anon4206dd0d0111::MachExceptionRaiseRequest297 MachExceptionRaiseRequest() {
298 memset(this, 0xa5, sizeof(*this));
299 Head.msgh_bits =
300 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND) |
301 MACH_MSGH_BITS_COMPLEX;
302 Head.msgh_size = sizeof(*this) - sizeof(trailer);
303 Head.msgh_remote_port = kClientRemotePort;
304 Head.msgh_local_port = kServerLocalPort;
305 Head.msgh_id = 2405;
306 msgh_body.msgh_descriptor_count = 2;
307 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort);
308 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort);
309 NDR = NDR_record;
310 exception = kExceptionType;
311 codeCnt = 2;
312 code[0] = kTestMachExceptionCodes[0];
313 code[1] = kTestMachExceptionCodes[1];
314 }
315
316 mach_msg_header_t Head;
317 mach_msg_body_t msgh_body;
318 mach_msg_port_descriptor_t thread;
319 mach_msg_port_descriptor_t task;
320 NDR_record_t NDR;
321 exception_type_t exception;
322 mach_msg_type_number_t codeCnt;
323 int64_t code[2];
324 mach_msg_trailer_t trailer;
325 };
326
327 // The reply messages for exception_raise and mach_exception_raise are
328 // identical.
329 using MachExceptionRaiseReply = ExceptionRaiseReply;
330
331 struct __attribute__((packed, aligned(4))) MachExceptionRaiseStateRequest {
MachExceptionRaiseStateRequestcrashpad::test::__anon4206dd0d0111::MachExceptionRaiseStateRequest332 MachExceptionRaiseStateRequest() {
333 memset(this, 0xa5, sizeof(*this));
334 Head.msgh_bits =
335 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND);
336 Head.msgh_size = sizeof(*this) - sizeof(trailer);
337 Head.msgh_remote_port = kClientRemotePort;
338 Head.msgh_local_port = kServerLocalPort;
339 Head.msgh_id = 2406;
340 NDR = NDR_record;
341 exception = kExceptionType;
342 codeCnt = 2;
343 code[0] = kTestMachExceptionCodes[0];
344 code[1] = kTestMachExceptionCodes[1];
345 flavor = kThreadStateFlavor;
346 old_stateCnt = kThreadStateFlavorCount;
347
348 // Adjust the message size for the data that it’s actually carrying, which
349 // may be smaller than the maximum that it can carry.
350 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state);
351 }
352
353 // Because the message size has been adjusted, the trailer may not appear in
354 // its home member variable. This computes the actual address of the trailer.
Trailercrashpad::test::__anon4206dd0d0111::MachExceptionRaiseStateRequest355 const mach_msg_trailer_t* Trailer() const {
356 return MachMessageTrailerFromHeader(&Head);
357 }
358
359 mach_msg_header_t Head;
360 NDR_record_t NDR;
361 exception_type_t exception;
362 mach_msg_type_number_t codeCnt;
363 int64_t code[2];
364 int flavor;
365 mach_msg_type_number_t old_stateCnt;
366 natural_t old_state[THREAD_STATE_MAX];
367 mach_msg_trailer_t trailer;
368 };
369
370 // The reply messages for exception_raise_state and mach_exception_raise_state
371 // are identical.
372 using MachExceptionRaiseStateReply = ExceptionRaiseStateReply;
373
374 struct __attribute__((packed,
375 aligned(4))) MachExceptionRaiseStateIdentityRequest {
MachExceptionRaiseStateIdentityRequestcrashpad::test::__anon4206dd0d0111::MachExceptionRaiseStateIdentityRequest376 MachExceptionRaiseStateIdentityRequest() {
377 memset(this, 0xa5, sizeof(*this));
378 Head.msgh_bits =
379 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND) |
380 MACH_MSGH_BITS_COMPLEX;
381 Head.msgh_size = sizeof(*this) - sizeof(trailer);
382 Head.msgh_remote_port = kClientRemotePort;
383 Head.msgh_local_port = kServerLocalPort;
384 Head.msgh_id = 2407;
385 msgh_body.msgh_descriptor_count = 2;
386 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort);
387 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort);
388 NDR = NDR_record;
389 exception = kExceptionType;
390 codeCnt = 2;
391 code[0] = kTestMachExceptionCodes[0];
392 code[1] = kTestMachExceptionCodes[1];
393 flavor = kThreadStateFlavor;
394 old_stateCnt = kThreadStateFlavorCount;
395
396 // Adjust the message size for the data that it’s actually carrying, which
397 // may be smaller than the maximum that it can carry.
398 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state);
399 }
400
401 // Because the message size has been adjusted, the trailer may not appear in
402 // its home member variable. This computes the actual address of the trailer.
Trailercrashpad::test::__anon4206dd0d0111::MachExceptionRaiseStateIdentityRequest403 const mach_msg_trailer_t* Trailer() const {
404 return MachMessageTrailerFromHeader(&Head);
405 }
406
407 mach_msg_header_t Head;
408 mach_msg_body_t msgh_body;
409 mach_msg_port_descriptor_t thread;
410 mach_msg_port_descriptor_t task;
411 NDR_record_t NDR;
412 exception_type_t exception;
413 mach_msg_type_number_t codeCnt;
414 int64_t code[2];
415 int flavor;
416 mach_msg_type_number_t old_stateCnt;
417 natural_t old_state[THREAD_STATE_MAX];
418 mach_msg_trailer_t trailer;
419 };
420
421 // The reply messages for exception_raise_state_identity and
422 // mach_exception_raise_state_identity are identical.
423 using MachExceptionRaiseStateIdentityReply = ExceptionRaiseStateIdentityReply;
424
425 // InvalidRequest and BadIDErrorReply are used to test that
426 // UniversalMachExcServer deals appropriately with messages that it does not
427 // understand: messages with an unknown Head.msgh_id.
428
429 struct InvalidRequest : public mach_msg_empty_send_t {
InvalidRequestcrashpad::test::__anon4206dd0d0111::InvalidRequest430 explicit InvalidRequest(mach_msg_id_t id) {
431 memset(this, 0xa5, sizeof(*this));
432 header.msgh_bits =
433 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND);
434 header.msgh_size = sizeof(*this);
435 header.msgh_remote_port = kClientRemotePort;
436 header.msgh_local_port = kServerLocalPort;
437 header.msgh_id = id;
438 }
439 };
440
441 struct BadIDErrorReply : public mig_reply_error_t {
BadIDErrorReplycrashpad::test::__anon4206dd0d0111::BadIDErrorReply442 BadIDErrorReply() {
443 memset(this, 0x5a, sizeof(*this));
444 RetCode = KERN_FAILURE;
445 }
446
Verifycrashpad::test::__anon4206dd0d0111::BadIDErrorReply447 void Verify(mach_msg_id_t id) {
448 EXPECT_EQ(Head.msgh_bits,
449 implicit_cast<mach_msg_bits_t>(
450 MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0)));
451 EXPECT_EQ(Head.msgh_size, sizeof(*this));
452 EXPECT_EQ(Head.msgh_remote_port, kClientRemotePort);
453 EXPECT_EQ(Head.msgh_local_port, kMachPortNull);
454 EXPECT_EQ(Head.msgh_id, id + 100);
455 EXPECT_EQ(memcmp(&NDR, &NDR_record, sizeof(NDR)), 0);
456 EXPECT_EQ(RetCode, MIG_BAD_ID);
457 }
458 };
459
460 class MockUniversalMachExcServer : public UniversalMachExcServer::Interface {
461 public:
462 struct ConstExceptionCodes {
463 const mach_exception_data_type_t* code;
464 mach_msg_type_number_t code_count;
465 };
466 struct ThreadStateAndCount {
467 thread_state_t state;
468 mach_msg_type_number_t* state_count;
469 };
470 struct ConstThreadStateAndCount {
471 ConstThreadState state;
472 mach_msg_type_number_t* state_count;
473 };
474
475 // UniversalMachExcServer::Interface:
476
477 // CatchMachException is the method to mock, but it has 13 parameters, and
478 // Google Mock can only mock methods with up to 10 parameters. Coalesce some
479 // related parameters together into structs, and call a mocked method.
CatchMachException(exception_behavior_t behavior,exception_handler_t exception_port,thread_t thread,task_t task,exception_type_t exception,const mach_exception_data_type_t * code,mach_msg_type_number_t code_count,thread_state_flavor_t * flavor,ConstThreadState old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count,const mach_msg_trailer_t * trailer,bool * destroy_complex_request)480 virtual kern_return_t CatchMachException(
481 exception_behavior_t behavior,
482 exception_handler_t exception_port,
483 thread_t thread,
484 task_t task,
485 exception_type_t exception,
486 const mach_exception_data_type_t* code,
487 mach_msg_type_number_t code_count,
488 thread_state_flavor_t* flavor,
489 ConstThreadState old_state,
490 mach_msg_type_number_t old_state_count,
491 thread_state_t new_state,
492 mach_msg_type_number_t* new_state_count,
493 const mach_msg_trailer_t* trailer,
494 bool* destroy_complex_request) override {
495 *destroy_complex_request = true;
496 const ConstExceptionCodes exception_codes = {code, code_count};
497 const ConstThreadStateAndCount old_thread_state = {old_state,
498 &old_state_count};
499 ThreadStateAndCount new_thread_state = {new_state, new_state_count};
500 return MockCatchMachException(behavior,
501 exception_port,
502 thread,
503 task,
504 exception,
505 &exception_codes,
506 flavor,
507 &old_thread_state,
508 &new_thread_state,
509 trailer);
510 }
511
512 MOCK_METHOD10(MockCatchMachException,
513 kern_return_t(exception_behavior_t behavior,
514 exception_handler_t exception_port,
515 thread_t thread,
516 task_t task,
517 exception_type_t exception,
518 const ConstExceptionCodes* exception_codes,
519 thread_state_flavor_t* flavor,
520 const ConstThreadStateAndCount* old_thread_state,
521 ThreadStateAndCount* new_thread_state,
522 const mach_msg_trailer_t* trailer));
523 };
524
525 // Matcher for ConstExceptionCodes, testing that it carries 2 codes matching
526 // code_0 and code_1.
527 MATCHER_P2(AreExceptionCodes, code_0, code_1, "") {
528 if (!arg) {
529 return false;
530 }
531
532 if (arg->code_count == 2 && arg->code[0] == code_0 &&
533 arg->code[1] == code_1) {
534 return true;
535 }
536
537 *result_listener << "codes (";
538 for (size_t index = 0; index < arg->code_count; ++index) {
539 *result_listener << arg->code[index];
540 if (index < arg->code_count - 1) {
541 *result_listener << ", ";
542 }
543 }
544 *result_listener << ")";
545
546 return false;
547 }
548
549 // Matcher for ThreadStateAndCount and ConstThreadStateAndCount, testing that
550 // *state_count is present and matches the specified value. If 0 is specified
551 // for the count, |state| must be nullptr (not present), otherwise |state| must
552 // not be nullptr (present).
553 MATCHER_P(IsThreadStateAndCount, state_count, "") {
554 if (!arg) {
555 return false;
556 }
557 if (!arg->state_count) {
558 *result_listener << "state_count nullptr";
559 return false;
560 }
561 if (*(arg->state_count) != state_count) {
562 *result_listener << "*state_count " << *(arg->state_count);
563 return false;
564 }
565 if (state_count) {
566 if (!arg->state) {
567 *result_listener << "*state_count " << state_count << ", state nullptr";
568 return false;
569 }
570 } else {
571 if (arg->state) {
572 *result_listener << "*state_count 0, state non-nullptr (" << arg->state
573 << ")";
574 return false;
575 }
576 }
577 return true;
578 }
579
580 template <typename T>
581 class ScopedDefaultValue {
582 public:
ScopedDefaultValue(const T & default_value)583 explicit ScopedDefaultValue(const T& default_value) {
584 DefaultValue<T>::Set(default_value);
585 }
586
~ScopedDefaultValue()587 ~ScopedDefaultValue() { DefaultValue<T>::Clear(); }
588 };
589
TEST(ExcServerVariants,MockExceptionRaise)590 TEST(ExcServerVariants, MockExceptionRaise) {
591 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
592
593 MockUniversalMachExcServer server;
594 UniversalMachExcServer universal_mach_exc_server(&server);
595
596 std::set<mach_msg_id_t> ids =
597 universal_mach_exc_server.MachMessageServerRequestIDs();
598 EXPECT_NE(ids.find(2401), ids.end()); // There is no constant for this.
599
600 ExceptionRaiseRequest request;
601 EXPECT_LE(request.Head.msgh_size,
602 universal_mach_exc_server.MachMessageServerRequestSize());
603
604 ExceptionRaiseReply reply;
605 EXPECT_LE(sizeof(reply),
606 universal_mach_exc_server.MachMessageServerReplySize());
607
608 constexpr exception_behavior_t kExceptionBehavior = EXCEPTION_DEFAULT;
609
610 EXPECT_CALL(server,
611 MockCatchMachException(kExceptionBehavior,
612 kServerLocalPort,
613 kExceptionThreadPort,
614 kExceptionTaskPort,
615 kExceptionType,
616 AreExceptionCodes(kTestExceptonCodes[0],
617 kTestExceptonCodes[1]),
618 Pointee(Eq(THREAD_STATE_NONE)),
619 IsThreadStateAndCount(0u),
620 IsThreadStateAndCount(0u),
621 Eq(&request.trailer)))
622 .WillOnce(Return(KERN_SUCCESS))
623 .RetiresOnSaturation();
624
625 bool destroy_complex_request = false;
626 EXPECT_TRUE(universal_mach_exc_server.MachMessageServerFunction(
627 reinterpret_cast<mach_msg_header_t*>(&request),
628 reinterpret_cast<mach_msg_header_t*>(&reply),
629 &destroy_complex_request));
630 EXPECT_TRUE(destroy_complex_request);
631
632 reply.Verify(kExceptionBehavior);
633 }
634
TEST(ExcServerVariants,MockExceptionRaiseState)635 TEST(ExcServerVariants, MockExceptionRaiseState) {
636 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
637
638 MockUniversalMachExcServer server;
639 UniversalMachExcServer universal_mach_exc_server(&server);
640
641 std::set<mach_msg_id_t> ids =
642 universal_mach_exc_server.MachMessageServerRequestIDs();
643 EXPECT_NE(ids.find(2402), ids.end()); // There is no constant for this.
644
645 ExceptionRaiseStateRequest request;
646 EXPECT_LE(request.Head.msgh_size,
647 universal_mach_exc_server.MachMessageServerRequestSize());
648
649 ExceptionRaiseStateReply reply;
650 EXPECT_LE(sizeof(reply),
651 universal_mach_exc_server.MachMessageServerReplySize());
652
653 constexpr exception_behavior_t kExceptionBehavior = EXCEPTION_STATE;
654
655 EXPECT_CALL(
656 server,
657 MockCatchMachException(
658 kExceptionBehavior,
659 kServerLocalPort,
660 THREAD_NULL,
661 TASK_NULL,
662 kExceptionType,
663 AreExceptionCodes(kTestExceptonCodes[0], kTestExceptonCodes[1]),
664 Pointee(Eq(kThreadStateFlavor)),
665 IsThreadStateAndCount(kThreadStateFlavorCount),
666 IsThreadStateAndCount(base::size(reply.new_state)),
667 Eq(request.Trailer())))
668 .WillOnce(Return(KERN_SUCCESS))
669 .RetiresOnSaturation();
670
671 bool destroy_complex_request = false;
672 EXPECT_TRUE(universal_mach_exc_server.MachMessageServerFunction(
673 reinterpret_cast<mach_msg_header_t*>(&request),
674 reinterpret_cast<mach_msg_header_t*>(&reply),
675 &destroy_complex_request));
676
677 // The request wasn’t complex, so nothing got a chance to change the value of
678 // this variable.
679 EXPECT_FALSE(destroy_complex_request);
680
681 reply.Verify(kExceptionBehavior);
682 }
683
TEST(ExcServerVariants,MockExceptionRaiseStateIdentity)684 TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) {
685 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
686
687 MockUniversalMachExcServer server;
688 UniversalMachExcServer universal_mach_exc_server(&server);
689
690 std::set<mach_msg_id_t> ids =
691 universal_mach_exc_server.MachMessageServerRequestIDs();
692 EXPECT_NE(ids.find(2403), ids.end()); // There is no constant for this.
693
694 ExceptionRaiseStateIdentityRequest request;
695 EXPECT_LE(request.Head.msgh_size,
696 universal_mach_exc_server.MachMessageServerRequestSize());
697
698 ExceptionRaiseStateIdentityReply reply;
699 EXPECT_LE(sizeof(reply),
700 universal_mach_exc_server.MachMessageServerReplySize());
701
702 constexpr exception_behavior_t kExceptionBehavior = EXCEPTION_STATE_IDENTITY;
703
704 EXPECT_CALL(
705 server,
706 MockCatchMachException(
707 kExceptionBehavior,
708 kServerLocalPort,
709 kExceptionThreadPort,
710 kExceptionTaskPort,
711 kExceptionType,
712 AreExceptionCodes(kTestExceptonCodes[0], kTestExceptonCodes[1]),
713 Pointee(Eq(kThreadStateFlavor)),
714 IsThreadStateAndCount(kThreadStateFlavorCount),
715 IsThreadStateAndCount(base::size(reply.new_state)),
716 Eq(request.Trailer())))
717 .WillOnce(Return(KERN_SUCCESS))
718 .RetiresOnSaturation();
719
720 bool destroy_complex_request = false;
721 EXPECT_TRUE(universal_mach_exc_server.MachMessageServerFunction(
722 reinterpret_cast<mach_msg_header_t*>(&request),
723 reinterpret_cast<mach_msg_header_t*>(&reply),
724 &destroy_complex_request));
725 EXPECT_TRUE(destroy_complex_request);
726
727 reply.Verify(kExceptionBehavior);
728 }
729
TEST(ExcServerVariants,MockMachExceptionRaise)730 TEST(ExcServerVariants, MockMachExceptionRaise) {
731 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
732
733 MockUniversalMachExcServer server;
734 UniversalMachExcServer universal_mach_exc_server(&server);
735
736 std::set<mach_msg_id_t> ids =
737 universal_mach_exc_server.MachMessageServerRequestIDs();
738 EXPECT_NE(ids.find(2405), ids.end()); // There is no constant for this.
739
740 MachExceptionRaiseRequest request;
741 EXPECT_LE(request.Head.msgh_size,
742 universal_mach_exc_server.MachMessageServerRequestSize());
743
744 MachExceptionRaiseReply reply;
745 EXPECT_LE(sizeof(reply),
746 universal_mach_exc_server.MachMessageServerReplySize());
747
748 constexpr exception_behavior_t kExceptionBehavior =
749 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES;
750
751 EXPECT_CALL(
752 server,
753 MockCatchMachException(kExceptionBehavior,
754 kServerLocalPort,
755 kExceptionThreadPort,
756 kExceptionTaskPort,
757 kExceptionType,
758 AreExceptionCodes(kTestMachExceptionCodes[0],
759 kTestMachExceptionCodes[1]),
760 Pointee(Eq(THREAD_STATE_NONE)),
761 IsThreadStateAndCount(0u),
762 IsThreadStateAndCount(0u),
763 Eq(&request.trailer)))
764 .WillOnce(Return(KERN_SUCCESS))
765 .RetiresOnSaturation();
766
767 bool destroy_complex_request = false;
768 EXPECT_TRUE(universal_mach_exc_server.MachMessageServerFunction(
769 reinterpret_cast<mach_msg_header_t*>(&request),
770 reinterpret_cast<mach_msg_header_t*>(&reply),
771 &destroy_complex_request));
772 EXPECT_TRUE(destroy_complex_request);
773
774 reply.Verify(kExceptionBehavior);
775 }
776
TEST(ExcServerVariants,MockMachExceptionRaiseState)777 TEST(ExcServerVariants, MockMachExceptionRaiseState) {
778 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
779
780 MockUniversalMachExcServer server;
781 UniversalMachExcServer universal_mach_exc_server(&server);
782
783 std::set<mach_msg_id_t> ids =
784 universal_mach_exc_server.MachMessageServerRequestIDs();
785 EXPECT_NE(ids.find(2406), ids.end()); // There is no constant for this.
786
787 MachExceptionRaiseStateRequest request;
788 EXPECT_LE(request.Head.msgh_size,
789 universal_mach_exc_server.MachMessageServerRequestSize());
790
791 MachExceptionRaiseStateReply reply;
792 EXPECT_LE(sizeof(reply),
793 universal_mach_exc_server.MachMessageServerReplySize());
794
795 constexpr exception_behavior_t kExceptionBehavior =
796 EXCEPTION_STATE | MACH_EXCEPTION_CODES;
797
798 EXPECT_CALL(
799 server,
800 MockCatchMachException(kExceptionBehavior,
801 kServerLocalPort,
802 THREAD_NULL,
803 TASK_NULL,
804 kExceptionType,
805 AreExceptionCodes(kTestMachExceptionCodes[0],
806 kTestMachExceptionCodes[1]),
807 Pointee(Eq(kThreadStateFlavor)),
808 IsThreadStateAndCount(kThreadStateFlavorCount),
809 IsThreadStateAndCount(base::size(reply.new_state)),
810 Eq(request.Trailer())))
811 .WillOnce(Return(KERN_SUCCESS))
812 .RetiresOnSaturation();
813
814 bool destroy_complex_request = false;
815 EXPECT_TRUE(universal_mach_exc_server.MachMessageServerFunction(
816 reinterpret_cast<mach_msg_header_t*>(&request),
817 reinterpret_cast<mach_msg_header_t*>(&reply),
818 &destroy_complex_request));
819
820 // The request wasn’t complex, so nothing got a chance to change the value of
821 // this variable.
822 EXPECT_FALSE(destroy_complex_request);
823
824 reply.Verify(kExceptionBehavior);
825 }
826
TEST(ExcServerVariants,MockMachExceptionRaiseStateIdentity)827 TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) {
828 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
829
830 MockUniversalMachExcServer server;
831 UniversalMachExcServer universal_mach_exc_server(&server);
832
833 std::set<mach_msg_id_t> ids =
834 universal_mach_exc_server.MachMessageServerRequestIDs();
835 EXPECT_NE(ids.find(2407), ids.end()); // There is no constant for this.
836
837 MachExceptionRaiseStateIdentityRequest request;
838 EXPECT_LE(request.Head.msgh_size,
839 universal_mach_exc_server.MachMessageServerRequestSize());
840
841 MachExceptionRaiseStateIdentityReply reply;
842 EXPECT_LE(sizeof(reply),
843 universal_mach_exc_server.MachMessageServerReplySize());
844
845 constexpr exception_behavior_t kExceptionBehavior =
846 EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES;
847
848 EXPECT_CALL(
849 server,
850 MockCatchMachException(kExceptionBehavior,
851 kServerLocalPort,
852 kExceptionThreadPort,
853 kExceptionTaskPort,
854 kExceptionType,
855 AreExceptionCodes(kTestMachExceptionCodes[0],
856 kTestMachExceptionCodes[1]),
857 Pointee(Eq(kThreadStateFlavor)),
858 IsThreadStateAndCount(kThreadStateFlavorCount),
859 IsThreadStateAndCount(base::size(reply.new_state)),
860 Eq(request.Trailer())))
861 .WillOnce(Return(KERN_SUCCESS))
862 .RetiresOnSaturation();
863
864 bool destroy_complex_request = false;
865 EXPECT_TRUE(universal_mach_exc_server.MachMessageServerFunction(
866 reinterpret_cast<mach_msg_header_t*>(&request),
867 reinterpret_cast<mach_msg_header_t*>(&reply),
868 &destroy_complex_request));
869 EXPECT_TRUE(destroy_complex_request);
870
871 reply.Verify(kExceptionBehavior);
872 }
873
TEST(ExcServerVariants,MockUnknownID)874 TEST(ExcServerVariants, MockUnknownID) {
875 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
876
877 MockUniversalMachExcServer server;
878 UniversalMachExcServer universal_mach_exc_server(&server);
879
880 // Make sure that a message with an unknown ID is handled appropriately.
881 // UniversalMachExcServer should not dispatch the message to
882 // MachMessageServerFunction, but should generate a MIG_BAD_ID error reply.
883
884 static constexpr mach_msg_id_t unknown_ids[] = {
885 // Reasonable things to check.
886 -101,
887 -100,
888 -99,
889 -1,
890 0,
891 1,
892 99,
893 100,
894 101,
895
896 // Invalid IDs right around valid ones.
897 2400,
898 2404,
899 2408,
900
901 // Valid and invalid IDs in the range used for replies, not requests.
902 2500,
903 2501,
904 2502,
905 2503,
906 2504,
907 2505,
908 2506,
909 2507,
910 2508,
911 };
912
913 for (size_t index = 0; index < base::size(unknown_ids); ++index) {
914 mach_msg_id_t id = unknown_ids[index];
915
916 SCOPED_TRACE(base::StringPrintf("unknown id %d", id));
917
918 std::set<mach_msg_id_t> ids =
919 universal_mach_exc_server.MachMessageServerRequestIDs();
920 EXPECT_EQ(ids.find(id), ids.end());
921
922 InvalidRequest request(id);
923 EXPECT_LE(sizeof(request),
924 universal_mach_exc_server.MachMessageServerRequestSize());
925
926 BadIDErrorReply reply;
927 EXPECT_LE(sizeof(reply),
928 universal_mach_exc_server.MachMessageServerReplySize());
929
930 bool destroy_complex_request = false;
931 EXPECT_FALSE(universal_mach_exc_server.MachMessageServerFunction(
932 reinterpret_cast<mach_msg_header_t*>(&request),
933 reinterpret_cast<mach_msg_header_t*>(&reply),
934 &destroy_complex_request));
935
936 // The request wasn’t handled, nothing got a chance to change the value of
937 // this variable. MachMessageServer would destroy the request if it was
938 // complex, regardless of what was done to this variable, because the
939 // return code was not KERN_SUCCESS or MIG_NO_REPLY.
940 EXPECT_FALSE(destroy_complex_request);
941
942 reply.Verify(id);
943 }
944 }
945
TEST(ExcServerVariants,MachMessageServerRequestIDs)946 TEST(ExcServerVariants, MachMessageServerRequestIDs) {
947 std::set<mach_msg_id_t> expect_request_ids;
948
949 // There are no constants for these.
950 expect_request_ids.insert(2401);
951 expect_request_ids.insert(2402);
952 expect_request_ids.insert(2403);
953 expect_request_ids.insert(2405);
954 expect_request_ids.insert(2406);
955 expect_request_ids.insert(2407);
956
957 MockUniversalMachExcServer server;
958 UniversalMachExcServer universal_mach_exc_server(&server);
959
960 EXPECT_EQ(universal_mach_exc_server.MachMessageServerRequestIDs(),
961 expect_request_ids);
962 }
963
964 #if defined(OS_MAC)
965
966 class TestExcServerVariants : public MachMultiprocess,
967 public UniversalMachExcServer::Interface {
968 public:
TestExcServerVariants(exception_behavior_t behavior,thread_state_flavor_t flavor,mach_msg_type_number_t state_count)969 TestExcServerVariants(exception_behavior_t behavior,
970 thread_state_flavor_t flavor,
971 mach_msg_type_number_t state_count)
972 : MachMultiprocess(),
973 UniversalMachExcServer::Interface(),
974 behavior_(behavior),
975 flavor_(flavor),
976 state_count_(state_count),
977 handled_(false) {
978 SetExpectedChildTerminationBuiltinTrap();
979 }
980
981 // UniversalMachExcServer::Interface:
982
CatchMachException(exception_behavior_t behavior,exception_handler_t exception_port,thread_t thread,task_t task,exception_type_t exception,const mach_exception_data_type_t * code,mach_msg_type_number_t code_count,thread_state_flavor_t * flavor,ConstThreadState old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count,const mach_msg_trailer_t * trailer,bool * destroy_complex_request)983 virtual kern_return_t CatchMachException(
984 exception_behavior_t behavior,
985 exception_handler_t exception_port,
986 thread_t thread,
987 task_t task,
988 exception_type_t exception,
989 const mach_exception_data_type_t* code,
990 mach_msg_type_number_t code_count,
991 thread_state_flavor_t* flavor,
992 ConstThreadState old_state,
993 mach_msg_type_number_t old_state_count,
994 thread_state_t new_state,
995 mach_msg_type_number_t* new_state_count,
996 const mach_msg_trailer_t* trailer,
997 bool* destroy_complex_request) override {
998 *destroy_complex_request = true;
999
1000 EXPECT_FALSE(handled_);
1001 handled_ = true;
1002
1003 EXPECT_EQ(behavior, behavior_);
1004
1005 EXPECT_EQ(exception_port, LocalPort());
1006
1007 if (ExceptionBehaviorHasIdentity(behavior)) {
1008 EXPECT_NE(thread, THREAD_NULL);
1009 EXPECT_EQ(task, ChildTask());
1010 } else {
1011 EXPECT_EQ(thread, THREAD_NULL);
1012 EXPECT_EQ(task, TASK_NULL);
1013 }
1014
1015 EXPECT_EQ(exception, EXC_CRASH);
1016 EXPECT_EQ(code_count, 2u);
1017
1018 // The exception and code_count checks above would ideally use ASSERT_EQ so
1019 // that the next conditional would not be necessary, but ASSERT_* requires a
1020 // function returning type void, and the interface dictates otherwise here.
1021 if (exception == EXC_CRASH && code_count >= 1) {
1022 int signal;
1023 ExcCrashRecoverOriginalException(code[0], nullptr, &signal);
1024 }
1025
1026 const bool has_state = ExceptionBehaviorHasState(behavior);
1027 if (has_state) {
1028 EXPECT_EQ(*flavor, flavor_);
1029 EXPECT_EQ(old_state_count, state_count_);
1030 EXPECT_NE(old_state, nullptr);
1031 EXPECT_EQ(*new_state_count,
1032 implicit_cast<mach_msg_type_number_t>(THREAD_STATE_MAX));
1033 EXPECT_NE(new_state, nullptr);
1034 } else {
1035 EXPECT_EQ(*flavor, THREAD_STATE_NONE);
1036 EXPECT_EQ(old_state_count, 0u);
1037 EXPECT_EQ(old_state, nullptr);
1038 EXPECT_EQ(*new_state_count, 0u);
1039 EXPECT_EQ(new_state, nullptr);
1040 }
1041
1042 EXPECT_EQ(
1043 trailer->msgh_trailer_type,
1044 implicit_cast<mach_msg_trailer_type_t>(MACH_MSG_TRAILER_FORMAT_0));
1045 EXPECT_EQ(trailer->msgh_trailer_size,
1046 REQUESTED_TRAILER_SIZE(kMachMessageOptions));
1047
1048 ExcServerCopyState(
1049 behavior, old_state, old_state_count, new_state, new_state_count);
1050
1051 return ExcServerSuccessfulReturnValue(exception, behavior, false);
1052 }
1053
1054 private:
1055 // MachMultiprocess:
1056
MachMultiprocessParent()1057 void MachMultiprocessParent() override {
1058 UniversalMachExcServer universal_mach_exc_server(this);
1059
1060 kern_return_t kr =
1061 MachMessageServer::Run(&universal_mach_exc_server,
1062 LocalPort(),
1063 kMachMessageOptions,
1064 MachMessageServer::kOneShot,
1065 MachMessageServer::kReceiveLargeError,
1066 kMachMessageTimeoutWaitIndefinitely);
1067 EXPECT_EQ(kr, KERN_SUCCESS)
1068 << MachErrorMessage(kr, "MachMessageServer::Run");
1069
1070 EXPECT_TRUE(handled_);
1071 }
1072
MachMultiprocessChild()1073 void MachMultiprocessChild() override {
1074 // Set the parent as the exception handler for EXC_CRASH.
1075 kern_return_t kr = task_set_exception_ports(
1076 mach_task_self(), EXC_MASK_CRASH, RemotePort(), behavior_, flavor_);
1077 ASSERT_EQ(kr, KERN_SUCCESS)
1078 << MachErrorMessage(kr, "task_set_exception_ports");
1079
1080 // Now crash.
1081 __builtin_trap();
1082 }
1083
1084 exception_behavior_t behavior_;
1085 thread_state_flavor_t flavor_;
1086 mach_msg_type_number_t state_count_;
1087 bool handled_;
1088
1089 static const mach_msg_option_t kMachMessageOptions =
1090 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0);
1091
1092 DISALLOW_COPY_AND_ASSIGN(TestExcServerVariants);
1093 };
1094
TEST(ExcServerVariants,ExceptionRaise)1095 TEST(ExcServerVariants, ExceptionRaise) {
1096 TestExcServerVariants test_exc_server_variants(
1097 EXCEPTION_DEFAULT, THREAD_STATE_NONE, 0);
1098 test_exc_server_variants.Run();
1099 }
1100
TEST(ExcServerVariants,ExceptionRaiseState)1101 TEST(ExcServerVariants, ExceptionRaiseState) {
1102 TestExcServerVariants test_exc_server_variants(
1103 EXCEPTION_STATE, MACHINE_THREAD_STATE, MACHINE_THREAD_STATE_COUNT);
1104 test_exc_server_variants.Run();
1105 }
1106
TEST(ExcServerVariants,ExceptionRaiseStateIdentity)1107 TEST(ExcServerVariants, ExceptionRaiseStateIdentity) {
1108 TestExcServerVariants test_exc_server_variants(EXCEPTION_STATE_IDENTITY,
1109 MACHINE_THREAD_STATE,
1110 MACHINE_THREAD_STATE_COUNT);
1111 test_exc_server_variants.Run();
1112 }
1113
TEST(ExcServerVariants,MachExceptionRaise)1114 TEST(ExcServerVariants, MachExceptionRaise) {
1115 TestExcServerVariants test_exc_server_variants(
1116 MACH_EXCEPTION_CODES | EXCEPTION_DEFAULT, THREAD_STATE_NONE, 0);
1117 test_exc_server_variants.Run();
1118 }
1119
TEST(ExcServerVariants,MachExceptionRaiseState)1120 TEST(ExcServerVariants, MachExceptionRaiseState) {
1121 TestExcServerVariants test_exc_server_variants(
1122 MACH_EXCEPTION_CODES | EXCEPTION_STATE,
1123 MACHINE_THREAD_STATE,
1124 MACHINE_THREAD_STATE_COUNT);
1125 test_exc_server_variants.Run();
1126 }
1127
TEST(ExcServerVariants,MachExceptionRaiseStateIdentity)1128 TEST(ExcServerVariants, MachExceptionRaiseStateIdentity) {
1129 TestExcServerVariants test_exc_server_variants(
1130 MACH_EXCEPTION_CODES | EXCEPTION_STATE_IDENTITY,
1131 MACHINE_THREAD_STATE,
1132 MACHINE_THREAD_STATE_COUNT);
1133 test_exc_server_variants.Run();
1134 }
1135
TEST(ExcServerVariants,ThreadStates)1136 TEST(ExcServerVariants, ThreadStates) {
1137 // So far, all of the tests worked with MACHINE_THREAD_STATE. Now try all of
1138 // the other thread state flavors that are expected to work.
1139
1140 static constexpr struct {
1141 thread_state_flavor_t flavor;
1142 mach_msg_type_number_t count;
1143 } test_data[] = {
1144 #if defined(ARCH_CPU_X86_FAMILY)
1145 // For the x86 family, exception handlers can only properly receive the
1146 // thread, float, and exception state flavors. There’s a bug in the kernel
1147 // that causes it to call thread_getstatus() (a wrapper for the more
1148 // familiar thread_get_state()) with an incorrect state buffer size
1149 // parameter when delivering an exception. 10.9.4
1150 // xnu-2422.110.17/osfmk/kern/exception.c exception_deliver() uses the
1151 // _MachineStateCount[] array indexed by the flavor number to obtain the
1152 // buffer size. 10.9.4 xnu-2422.110.17/osfmk/i386/pcb.c contains the
1153 // definition of this array for the x86 family. The slots corresponding to
1154 // thread, float, and exception state flavors in both native-width (32- and
1155 // 64-bit) and universal are correct, but the remaining elements in the
1156 // array are not. This includes elements that would correspond to debug and
1157 // AVX state flavors, so these cannot be tested here.
1158 //
1159 // When machine_thread_get_state() (the machine-specific implementation of
1160 // thread_get_state()) encounters an undersized buffer as reported by the
1161 // buffer size parameter, it returns KERN_INVALID_ARGUMENT, which causes
1162 // exception_deliver() to not actually deliver the exception and instead
1163 // return that error code to exception_triage() as well.
1164 //
1165 // This bug is filed as radar 18312067.
1166 //
1167 // Additionaly, the AVX state flavors are also not tested because they’re
1168 // not available on all CPUs and OS versions.
1169 {x86_THREAD_STATE, x86_THREAD_STATE_COUNT},
1170 {x86_FLOAT_STATE, x86_FLOAT_STATE_COUNT},
1171 {x86_EXCEPTION_STATE, x86_EXCEPTION_STATE_COUNT},
1172 #if defined(ARCH_CPU_X86)
1173 {x86_THREAD_STATE32, x86_THREAD_STATE32_COUNT},
1174 {x86_FLOAT_STATE32, x86_FLOAT_STATE32_COUNT},
1175 {x86_EXCEPTION_STATE32, x86_EXCEPTION_STATE32_COUNT},
1176 #elif defined(ARCH_CPU_X86_64)
1177 {x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT},
1178 {x86_FLOAT_STATE64, x86_FLOAT_STATE64_COUNT},
1179 {x86_EXCEPTION_STATE64, x86_EXCEPTION_STATE64_COUNT},
1180 #endif
1181 #elif defined(ARCH_CPU_ARM64)
1182 {ARM_UNIFIED_THREAD_STATE, ARM_UNIFIED_THREAD_STATE_COUNT},
1183 {ARM_THREAD_STATE64, ARM_THREAD_STATE64_COUNT},
1184 {ARM_NEON_STATE64, ARM_NEON_STATE64_COUNT},
1185 {ARM_EXCEPTION_STATE64, ARM_EXCEPTION_STATE64_COUNT},
1186 #else
1187 #error Port this test to your CPU architecture.
1188 #endif
1189 };
1190
1191 for (size_t index = 0; index < base::size(test_data); ++index) {
1192 const auto& test = test_data[index];
1193 SCOPED_TRACE(
1194 base::StringPrintf("index %zu, flavor %d", index, test.flavor));
1195
1196 TestExcServerVariants test_exc_server_variants(
1197 MACH_EXCEPTION_CODES | EXCEPTION_STATE_IDENTITY,
1198 test.flavor,
1199 test.count);
1200 test_exc_server_variants.Run();
1201 }
1202 }
1203
1204 #endif // OS_MAC
1205
TEST(ExcServerVariants,ExcServerSuccessfulReturnValue)1206 TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) {
1207 #if defined(OS_IOS)
1208 // iOS 9 ≅ OS X 10.11.
1209 const kern_return_t prefer_not_set_thread_state = KERN_SUCCESS;
1210 #else
1211 const kern_return_t prefer_not_set_thread_state =
1212 MacOSVersionNumber() < 10'11'00 ? MACH_RCV_PORT_DIED : KERN_SUCCESS;
1213 #endif
1214
1215 const struct {
1216 exception_type_t exception;
1217 exception_behavior_t behavior;
1218 bool set_thread_state;
1219 kern_return_t kr;
1220 } kTestData[] = {
1221 {EXC_CRASH, EXCEPTION_DEFAULT, false, KERN_SUCCESS},
1222 {EXC_CRASH, EXCEPTION_STATE, false, prefer_not_set_thread_state},
1223 {EXC_CRASH, EXCEPTION_STATE_IDENTITY, false, prefer_not_set_thread_state},
1224 {EXC_CRASH, kMachExceptionCodes | EXCEPTION_DEFAULT, false, KERN_SUCCESS},
1225 {EXC_CRASH,
1226 kMachExceptionCodes | EXCEPTION_STATE,
1227 false,
1228 prefer_not_set_thread_state},
1229 {EXC_CRASH,
1230 kMachExceptionCodes | EXCEPTION_STATE_IDENTITY,
1231 false,
1232 prefer_not_set_thread_state},
1233 {EXC_CRASH, EXCEPTION_DEFAULT, true, KERN_SUCCESS},
1234 {EXC_CRASH, EXCEPTION_STATE, true, KERN_SUCCESS},
1235 {EXC_CRASH, EXCEPTION_STATE_IDENTITY, true, KERN_SUCCESS},
1236 {EXC_CRASH, kMachExceptionCodes | EXCEPTION_DEFAULT, true, KERN_SUCCESS},
1237 {EXC_CRASH, kMachExceptionCodes | EXCEPTION_STATE, true, KERN_SUCCESS},
1238 {EXC_CRASH,
1239 kMachExceptionCodes | EXCEPTION_STATE_IDENTITY,
1240 true,
1241 KERN_SUCCESS},
1242 {EXC_BAD_ACCESS, EXCEPTION_DEFAULT, false, KERN_SUCCESS},
1243 {EXC_BAD_INSTRUCTION, EXCEPTION_STATE, false, MACH_RCV_PORT_DIED},
1244 {EXC_ARITHMETIC, EXCEPTION_STATE_IDENTITY, false, MACH_RCV_PORT_DIED},
1245 {EXC_EMULATION,
1246 kMachExceptionCodes | EXCEPTION_DEFAULT,
1247 false,
1248 KERN_SUCCESS},
1249 {EXC_SOFTWARE,
1250 kMachExceptionCodes | EXCEPTION_STATE,
1251 false,
1252 MACH_RCV_PORT_DIED},
1253 {EXC_BREAKPOINT,
1254 kMachExceptionCodes | EXCEPTION_STATE_IDENTITY,
1255 false,
1256 MACH_RCV_PORT_DIED},
1257 {EXC_SYSCALL, EXCEPTION_DEFAULT, true, KERN_SUCCESS},
1258 {EXC_MACH_SYSCALL, EXCEPTION_STATE, true, KERN_SUCCESS},
1259 {EXC_RPC_ALERT, EXCEPTION_STATE_IDENTITY, true, KERN_SUCCESS},
1260 {EXC_RESOURCE,
1261 kMachExceptionCodes | EXCEPTION_DEFAULT,
1262 true,
1263 KERN_SUCCESS},
1264 {EXC_GUARD, kMachExceptionCodes | EXCEPTION_STATE, true, KERN_SUCCESS},
1265 {EXC_CORPSE_NOTIFY,
1266 kMachExceptionCodes | EXCEPTION_STATE_IDENTITY,
1267 true,
1268 KERN_SUCCESS},
1269 };
1270
1271 for (size_t index = 0; index < base::size(kTestData); ++index) {
1272 const auto& test_data = kTestData[index];
1273 SCOPED_TRACE(
1274 base::StringPrintf("index %zu, behavior %d, set_thread_state %s",
1275 index,
1276 test_data.behavior,
1277 test_data.set_thread_state ? "true" : "false"));
1278
1279 EXPECT_EQ(ExcServerSuccessfulReturnValue(test_data.exception,
1280 test_data.behavior,
1281 test_data.set_thread_state),
1282 test_data.kr);
1283 }
1284 }
1285
TEST(ExcServerVariants,ExcServerCopyState)1286 TEST(ExcServerVariants, ExcServerCopyState) {
1287 static constexpr natural_t old_state[] = {1, 2, 3, 4, 5};
1288 natural_t new_state[10] = {};
1289
1290 constexpr mach_msg_type_number_t old_state_count = base::size(old_state);
1291 mach_msg_type_number_t new_state_count = base::size(new_state);
1292
1293 // EXCEPTION_DEFAULT (with or without MACH_EXCEPTION_CODES) is not
1294 // state-carrying. new_state and new_state_count should be untouched.
1295 ExcServerCopyState(EXCEPTION_DEFAULT,
1296 old_state,
1297 old_state_count,
1298 new_state,
1299 &new_state_count);
1300 EXPECT_EQ(new_state_count, base::size(new_state));
1301 for (size_t i = 0; i < base::size(new_state); ++i) {
1302 EXPECT_EQ(new_state[i], 0u) << "i " << i;
1303 }
1304
1305 ExcServerCopyState(MACH_EXCEPTION_CODES | EXCEPTION_DEFAULT,
1306 old_state,
1307 old_state_count,
1308 new_state,
1309 &new_state_count);
1310 EXPECT_EQ(new_state_count, base::size(new_state));
1311 for (size_t i = 0; i < base::size(new_state); ++i) {
1312 EXPECT_EQ(new_state[i], 0u) << "i " << i;
1313 }
1314
1315 // This is a state-carrying exception where old_state_count is small.
1316 mach_msg_type_number_t copy_limit = 2;
1317 ExcServerCopyState(
1318 EXCEPTION_STATE, old_state, copy_limit, new_state, &new_state_count);
1319 EXPECT_EQ(new_state_count, copy_limit);
1320 for (size_t i = 0; i < copy_limit; ++i) {
1321 EXPECT_EQ(new_state[i], old_state[i]) << "i " << i;
1322 }
1323 for (size_t i = copy_limit; i < base::size(new_state); ++i) {
1324 EXPECT_EQ(new_state[i], 0u) << "i " << i;
1325 }
1326
1327 // This is a state-carrying exception where new_state_count is small.
1328 copy_limit = 3;
1329 new_state_count = copy_limit;
1330 ExcServerCopyState(EXCEPTION_STATE_IDENTITY,
1331 old_state,
1332 old_state_count,
1333 new_state,
1334 &new_state_count);
1335 EXPECT_EQ(new_state_count, copy_limit);
1336 for (size_t i = 0; i < copy_limit; ++i) {
1337 EXPECT_EQ(new_state[i], old_state[i]) << "i " << i;
1338 }
1339 for (size_t i = copy_limit; i < base::size(new_state); ++i) {
1340 EXPECT_EQ(new_state[i], 0u) << "i " << i;
1341 }
1342
1343 // This is a state-carrying exception where all of old_state is copied to
1344 // new_state, which is large enough to receive it and then some.
1345 new_state_count = base::size(new_state);
1346 ExcServerCopyState(MACH_EXCEPTION_CODES | EXCEPTION_STATE_IDENTITY,
1347 old_state,
1348 old_state_count,
1349 new_state,
1350 &new_state_count);
1351 EXPECT_EQ(new_state_count, old_state_count);
1352 for (size_t i = 0; i < base::size(old_state); ++i) {
1353 EXPECT_EQ(new_state[i], old_state[i]) << "i " << i;
1354 }
1355 for (size_t i = base::size(old_state); i < base::size(new_state); ++i) {
1356 EXPECT_EQ(new_state[i], 0u) << "i " << i;
1357 }
1358 }
1359
1360 } // namespace
1361 } // namespace test
1362 } // namespace crashpad
1363