Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Side by Side Diff: util/mach/exc_client_variants_test.cc

Issue 567283002: Add exc_client_variants (UniversalRaiseException()) and its test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Rename to stay closer to the names traditionally used by Mach Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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_client_variants.h"
16
17 #include <mach/mach.h>
18 #include <pthread.h>
19 #include <string.h>
20
21 #include "base/basictypes.h"
22 #include "base/strings/stringprintf.h"
23 #include "gtest/gtest.h"
24 #include "util/mach/exc_server_variants.h"
25 #include "util/mach/mach_extensions.h"
26 #include "util/test/mac/mach_errors.h"
27 #include "util/test/mac/mach_multiprocess.h"
28
29 namespace {
30
31 using namespace crashpad;
32 using namespace crashpad::test;
33
34 class TestExcClientVariants : public UniversalMachExcServer,
35 public MachMultiprocess {
36 public:
37 TestExcClientVariants(exception_behavior_t behavior, bool all_fields)
38 : UniversalMachExcServer(),
39 MachMultiprocess(),
40 behavior_(behavior),
41 all_fields_(all_fields),
42 handled_(false) {
43 ++exception_;
44 ++exception_code_;
45 ++exception_subcode_;
46 }
47
48 // UniversalMachExcServer:
49
50 virtual kern_return_t CatchMachException(
51 exception_behavior_t behavior,
52 exception_handler_t exception_port,
53 thread_t thread,
54 task_t task,
55 exception_type_t exception,
56 const mach_exception_data_type_t* code,
57 mach_msg_type_number_t code_count,
58 thread_state_flavor_t* flavor,
59 const natural_t* old_state,
60 mach_msg_type_number_t old_state_count,
61 thread_state_t new_state,
62 mach_msg_type_number_t* new_state_count,
63 bool* destroy_complex_request) override {
64 *destroy_complex_request = true;
65
66 EXPECT_FALSE(handled_);
67 handled_ = true;
68
69 EXPECT_EQ(behavior_, behavior);
70 EXPECT_EQ(LocalPort(), exception_port);
71
72 if (HasIdentity()) {
73 EXPECT_NE(kMachPortNull, thread);
74 EXPECT_EQ(ChildTask(), task);
75 } else {
76 EXPECT_EQ(kMachPortNull, thread);
77 EXPECT_EQ(kMachPortNull, task);
78 }
79
80 mach_exception_code_t expect_code = exception_code_;
81 mach_exception_subcode_t expect_subcode = exception_subcode_;
82 if ((behavior & MACH_EXCEPTION_CODES) == 0) {
83 expect_code = static_cast<exception_data_type_t>(expect_code);
84 expect_subcode = static_cast<exception_data_type_t>(expect_subcode);
85 }
86
87 EXPECT_EQ(exception_, exception);
88 EXPECT_EQ(2u, code_count);
89 EXPECT_EQ(expect_code, code[0]);
90 EXPECT_EQ(expect_subcode, code[1]);
91
92 if (HasState()) {
93 EXPECT_EQ(exception_ + 10, *flavor);
94 EXPECT_EQ(MACHINE_THREAD_STATE_COUNT, old_state_count);
95 EXPECT_NE(static_cast<const natural_t*>(NULL), old_state);
96 EXPECT_EQ(static_cast<mach_msg_type_number_t>(THREAD_STATE_MAX),
97 *new_state_count);
98 EXPECT_NE(static_cast<natural_t*>(NULL), new_state);
99
100 for (size_t index = 0; index < old_state_count; ++index) {
101 EXPECT_EQ(index, old_state[index]);
102 }
103
104 // Use a flavor known to be different from the incoming flavor, for a test
105 // of the “out” side of the inout flavor parameter.
106 *flavor = exception_ + 20;
107 *new_state_count = MACHINE_THREAD_STATE_COUNT;
108
109 // Send a new state back to the client.
110 for (size_t index = 0; index < *new_state_count; ++index) {
111 EXPECT_EQ(0u, new_state[index]);
112 new_state[index] = MACHINE_THREAD_STATE_COUNT - index;
113 }
114 } else {
115 EXPECT_EQ(THREAD_STATE_NONE, *flavor);
116 EXPECT_EQ(0u, old_state_count);
117 EXPECT_EQ(NULL, old_state);
118 EXPECT_EQ(0u, *new_state_count);
119 EXPECT_EQ(NULL, new_state);
120 }
121
122 return KERN_SUCCESS;
123 }
124
125 private:
126 // MachMultiprocess:
127
128 virtual void MachMultiprocessParent() override {
129 kern_return_t kr = MachMessageServer::Run(this,
130 LocalPort(),
131 MACH_MSG_OPTION_NONE,
132 MachMessageServer::kOneShot,
133 MachMessageServer::kBlocking,
134 0);
135 EXPECT_EQ(KERN_SUCCESS, kr)
136 << MachErrorMessage(kr, "MachMessageServer::Run");
137
138 EXPECT_TRUE(handled_);
139 }
140
141 virtual void MachMultiprocessChild() override {
142 exception_type_t exception = exception_;
143 mach_exception_data_type_t code[] = {
Robert Sesek 2014/09/15 20:55:43 const?
144 exception_code_,
145 exception_subcode_
146 };
147
148 thread_t thread = MACH_PORT_NULL;
149 task_t task = MACH_PORT_NULL;
150 if (all_fields_ || HasIdentity()) {
151 thread = pthread_mach_thread_np(pthread_self());
Robert Sesek 2014/09/15 20:55:43 Why do you do this instead of just mach_thread_sel
152 task = mach_task_self();
153 }
154
155 thread_state_flavor_t flavor;
156 thread_state_flavor_t* flavor_p = NULL;
157 natural_t old_state[MACHINE_THREAD_STATE_COUNT];
158 thread_state_t old_state_p = NULL;
159 mach_msg_type_number_t old_state_count = 0;
160 natural_t new_state[THREAD_STATE_MAX];
161 thread_state_t new_state_p = NULL;
162 mach_msg_type_number_t new_state_count;
163 mach_msg_type_number_t* new_state_count_p = NULL;
164 if (all_fields_ || HasState()) {
165 // Pick a different flavor each time based on the value of exception_.
166 // These aren’t real flavors, it’s just for testing.
167 flavor = exception_ + 10;
168 flavor_p = &flavor;
169 for (size_t index = 0; index < arraysize(old_state); ++index) {
170 old_state[index] = index;
171 }
172 old_state_p = reinterpret_cast<thread_state_t>(&old_state);
173 old_state_count = arraysize(old_state);
174
175 // new_state and new_state_count are out parameters that the server should
176 // never see or use, so set them to bogus values. The call to the server
177 // should overwrite these.
178 memset(new_state, 0xa5, sizeof(new_state));
179 new_state_p = reinterpret_cast<thread_state_t>(&new_state);
180 new_state_count = 0x5a;
181 new_state_count_p = &new_state_count;
182 }
183
184 EXPECT_EQ(KERN_SUCCESS, UniversalExceptionRaise(behavior_,
185 RemotePort(),
186 thread,
187 task,
188 exception,
189 code,
190 arraysize(code),
191 flavor_p,
192 old_state_p,
193 old_state_count,
194 new_state_p,
195 new_state_count_p));
196
197 if (HasState()) {
198 // Verify the out parameters.
199
200 EXPECT_EQ(exception_ + 20, flavor);
201 EXPECT_EQ(MACHINE_THREAD_STATE_COUNT, new_state_count);
202
203 for (size_t index = 0; index < new_state_count; ++index) {
204 EXPECT_EQ(MACHINE_THREAD_STATE_COUNT - index, new_state[index]);
205 }
206 }
207 }
208
209 exception_behavior_t BasicBehavior() const {
210 return behavior_ & ~MACH_EXCEPTION_CODES;
211 }
212
213 bool HasIdentity() const {
214 exception_behavior_t basic_behavior = BasicBehavior();
215 return basic_behavior == EXCEPTION_DEFAULT ||
216 basic_behavior == EXCEPTION_STATE_IDENTITY;
217 }
218
219 bool HasState() const {
220 exception_behavior_t basic_behavior = BasicBehavior();
221 return basic_behavior == EXCEPTION_STATE ||
222 basic_behavior == EXCEPTION_STATE_IDENTITY;
223 }
224
225 // The behavior to test.
226 exception_behavior_t behavior_;
227
228 // If false, only fields required for the current value of behavior_ are set
229 // in a call to UniversalExceptionRaise(). The thread and task fields are only
230 // set for identity-carrying behaviors, and the flavor and state fields are
231 // only set for state-carrying behaviors. If true, all fields are set
232 // regardless of the behavior. Testing in both ways verifies that
233 // UniversalExceptionRaise() can tolerate the null arguments documented as
234 // usable when the behavior allows it, and that it ignores these arguments
235 // even when set when the behavior does not make use of them.
236 bool all_fields_;
237
238 // true if an exception message was handled.
239 bool handled_;
240
241 // These fields will increment for each instantiation of the test class.
242 static exception_type_t exception_;
243 static mach_exception_code_t exception_code_;
244 static mach_exception_subcode_t exception_subcode_;
245
246 DISALLOW_COPY_AND_ASSIGN(TestExcClientVariants);
247 };
248
249 exception_type_t TestExcClientVariants::exception_ = 0;
250
251 // exception_code_ and exception_subcode_ are always large enough to require
252 // 64 bits, so that when the 32-bit-only variants not using MACH_EXCEPITON_CODES
253 // are tested, the code and subcode fields can be checked for proper truncation.
254 mach_exception_code_t TestExcClientVariants::exception_code_ = 0x100000000;
255 mach_exception_subcode_t TestExcClientVariants::exception_subcode_ =
256 0xffffffff00000000;
257
258 TEST(ExcClientVariants, UniversalExceptionRaise) {
259 const exception_behavior_t kBehaviors[] = {
260 EXCEPTION_DEFAULT,
261 EXCEPTION_STATE,
262 EXCEPTION_STATE_IDENTITY,
263 kMachExceptionCodes | EXCEPTION_DEFAULT,
264 kMachExceptionCodes | EXCEPTION_STATE,
265 kMachExceptionCodes | EXCEPTION_STATE_IDENTITY,
266 };
267
268 for (size_t index = 0; index < arraysize(kBehaviors); ++index) {
269 exception_behavior_t behavior = kBehaviors[index];
270 SCOPED_TRACE(base::StringPrintf("index %zu, behavior %d", index, behavior));
271
272 {
273 SCOPED_TRACE("all_fields = false");
274
275 TestExcClientVariants test_exc_client_variants(behavior, false);
276 test_exc_client_variants.Run();
277 }
278
279 {
280 SCOPED_TRACE("all_fields = true");
281
282 TestExcClientVariants test_exc_client_variants(behavior, true);
283 test_exc_client_variants.Run();
284 }
285 }
286 }
287
288 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698