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