]>
Commit | Line | Data |
---|---|---|
39037602 A |
1 | // |
2 | // Tests.swift | |
3 | // | |
4 | // Some of these tests here verify that kdd is able to parse old | |
5 | // kcdata files and generate the correct output. To do so, we include | |
6 | // compressed versions of the raw kcdata and as well as the expected | |
7 | // plist output. | |
8 | // | |
9 | // NOTE: If you're adding sample data/plist files, you'll need to first | |
10 | // add them to the project and then make sure each is part of the | |
11 | // tests target. | |
12 | // | |
13 | // Other tests verify the expected behavior of libkdd for certain | |
14 | // situations. | |
15 | // | |
16 | // | |
17 | ||
18 | import XCTest | |
19 | import Foundation | |
20 | ||
21 | // Swift's bridging to uuid_t is awkward. | |
22 | ||
23 | func nsuuid2uuid_t(nsuuid : NSUUID) -> uuid_t { | |
24 | let dat = nsuuid2array(nsuuid) | |
25 | return nsarray2uuid(dat) | |
26 | } | |
27 | ||
28 | func nsarray2uuid(x : AnyObject) -> uuid_t { | |
29 | let a = x as! NSArray | |
30 | return uuid_t(UInt8(a[0] as! Int), | |
31 | UInt8(a[1] as! Int), | |
32 | UInt8(a[2] as! Int), | |
33 | UInt8(a[3] as! Int), | |
34 | UInt8(a[4] as! Int), | |
35 | UInt8(a[5] as! Int), | |
36 | UInt8(a[6] as! Int), | |
37 | UInt8(a[7] as! Int), | |
38 | UInt8(a[8] as! Int), | |
39 | UInt8(a[9] as! Int), | |
40 | UInt8(a[10] as! Int), | |
41 | UInt8(a[11] as! Int), | |
42 | UInt8(a[12] as! Int), | |
43 | UInt8(a[13] as! Int), | |
44 | UInt8(a[14] as! Int), | |
45 | UInt8(a[15] as! Int)) | |
46 | } | |
47 | ||
48 | func nsuuid2array(uuid : NSUUID) -> [Int] { | |
49 | var ret = [Int]() | |
50 | let ptr = UnsafeMutablePointer<UInt8>.alloc(16) | |
51 | ||
52 | defer { ptr.dealloc(16) } | |
53 | ||
54 | uuid.getUUIDBytes(ptr) | |
55 | for i in 0..<16 { | |
56 | ret.append(Int(ptr[i])) | |
57 | } | |
58 | return ret | |
59 | } | |
60 | ||
61 | func decompress(data:NSData) throws -> NSData { | |
62 | var stream = z_stream(next_in: nil, avail_in: 0, total_in: 0, next_out: nil, avail_out: 0, total_out: 0, msg: nil, state: nil, zalloc: nil, zfree: nil, opaque: nil, data_type: 0, adler: 0, reserved: 0) | |
63 | ||
64 | let bufsize : Int = 1000 | |
65 | let buffer = UnsafeMutablePointer<UInt8>.alloc(bufsize) | |
66 | defer { buffer.dealloc(bufsize) } | |
67 | let output = NSMutableData() | |
68 | stream.next_out = buffer | |
69 | stream.avail_out = UInt32(bufsize) | |
70 | stream.next_in = UnsafeMutablePointer(data.bytes) | |
71 | stream.avail_in = UInt32(data.length) | |
72 | inflateInit2_(&stream, 16+MAX_WBITS, ZLIB_VERSION, Int32(sizeof(z_stream))) | |
73 | ||
74 | while (true) { | |
75 | let z = inflate(&stream, Z_NO_FLUSH); | |
76 | if (z == Z_OK || z == Z_STREAM_END) { | |
77 | output.appendBytes(buffer, length: bufsize - Int(stream.avail_out)) | |
78 | stream.avail_out = UInt32(bufsize) | |
79 | stream.next_out = buffer | |
80 | if (z == Z_STREAM_END) { | |
81 | return output; | |
82 | } | |
83 | } else { | |
84 | throw NSError(domain: "zlib", code: Int(z), userInfo: nil) | |
85 | } | |
86 | } | |
87 | } | |
88 | ||
89 | ||
90 | ||
91 | class Tests: XCTestCase { | |
92 | ||
93 | override func setUp() { | |
94 | super.setUp() | |
95 | continueAfterFailure = false | |
96 | } | |
97 | ||
98 | override func tearDown() { | |
99 | // Put teardown code here. This method is called after the invocation of each test method in the class. | |
100 | super.tearDown() | |
101 | } | |
102 | ||
103 | func parseBuffer(buffer:NSData) throws -> NSDictionary { | |
104 | var error : NSError? | |
105 | guard let dict = parseKCDataBuffer(UnsafeMutablePointer(buffer.bytes), UInt32(buffer.length), &error) | |
106 | else { | |
107 | XCTAssert(error != nil) | |
108 | throw error! | |
109 | } | |
110 | return dict | |
111 | } | |
112 | ||
113 | func testPaddingFlags(pad : Int) { | |
114 | let buffer = NSMutableData(capacity:1000)! | |
115 | ||
116 | var item = kcdata_item() | |
117 | ||
118 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
119 | item.flags = 0 | |
120 | item.size = 0 | |
121 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
122 | ||
123 | item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO) | |
124 | item.flags = UInt64(pad) | |
125 | item.size = UInt32(sizeof(dyld_uuid_info_32)) | |
126 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
127 | ||
128 | let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")! | |
129 | ||
130 | var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid)) | |
131 | buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32)) | |
132 | ||
133 | item.type = KCDATA_TYPE_BUFFER_END | |
134 | item.flags = 0 | |
135 | item.size = 0 | |
136 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
137 | ||
138 | guard let dict = try? self.parseBuffer(buffer) | |
139 | else { XCTFail(); return; } | |
140 | ||
141 | var uuidarray = nsuuid2array(uuid) | |
142 | for _ in 0..<pad { | |
143 | uuidarray.removeLast() | |
144 | } | |
145 | ||
146 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42) | |
147 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == uuidarray) | |
148 | } | |
149 | ||
150 | func testPaddingFlags() { | |
151 | for i in 0..<15 { | |
152 | testPaddingFlags(i) | |
153 | } | |
154 | } | |
155 | ||
156 | func testBootArgs() { | |
157 | let s = "hello, I am some boot args" | |
158 | ||
159 | let buffer = NSMutableData(capacity:1000)! | |
160 | ||
161 | var item = kcdata_item() | |
162 | ||
163 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
164 | item.flags = 0 | |
165 | item.size = 0 | |
166 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
167 | ||
168 | item.type = UInt32(STACKSHOT_KCTYPE_BOOTARGS) | |
169 | item.flags = 0 | |
170 | item.size = UInt32(s.utf8.count + 1) | |
171 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
172 | s.nulTerminatedUTF8.withUnsafeBufferPointer({ | |
173 | buffer.appendBytes($0.baseAddress, length:s.utf8.count + 1) | |
174 | }) | |
175 | ||
176 | item.type = KCDATA_TYPE_BUFFER_END | |
177 | item.flags = 0 | |
178 | item.size = 0 | |
179 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
180 | ||
181 | guard let dict = try? self.parseBuffer(buffer) else { XCTFail(); return; } | |
182 | XCTAssert(dict["kcdata_crashinfo"]?["boot_args"] == s) | |
183 | } | |
184 | ||
185 | func testBootArgsMissingNul() { | |
186 | let s = "hello, I am some boot args" | |
187 | ||
188 | let buffer = NSMutableData(capacity:1000)! | |
189 | ||
190 | var item = kcdata_item() | |
191 | ||
192 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
193 | item.flags = 0 | |
194 | item.size = 0 | |
195 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
196 | ||
197 | item.type = UInt32(STACKSHOT_KCTYPE_BOOTARGS) | |
198 | item.flags = 0 | |
199 | item.size = UInt32(s.utf8.count) | |
200 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
201 | s.nulTerminatedUTF8.withUnsafeBufferPointer({ | |
202 | buffer.appendBytes($0.baseAddress, length:s.utf8.count) | |
203 | }) | |
204 | ||
205 | item.type = KCDATA_TYPE_BUFFER_END | |
206 | item.flags = 0 | |
207 | item.size = 0 | |
208 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
209 | ||
210 | XCTAssert( (try? self.parseBuffer(buffer)) == nil ) | |
211 | } | |
212 | ||
213 | func testLoadInfo() { | |
214 | let buffer = NSMutableData(capacity:1000)! | |
215 | ||
216 | var item = kcdata_item() | |
217 | ||
218 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
219 | item.flags = 0 | |
220 | item.size = 0 | |
221 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
222 | ||
223 | item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO) | |
224 | item.flags = 0 | |
225 | item.size = UInt32(sizeof(dyld_uuid_info_32)) | |
226 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
227 | ||
228 | let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")! | |
229 | ||
230 | var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid)) | |
231 | buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32)) | |
232 | ||
233 | item.type = KCDATA_TYPE_BUFFER_END | |
234 | item.flags = 0 | |
235 | item.size = 0 | |
236 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
237 | ||
238 | guard let dict = try? self.parseBuffer(buffer) | |
239 | else { XCTFail(); return; } | |
240 | ||
241 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42) | |
242 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == nsuuid2array(uuid)) | |
243 | } | |
244 | ||
245 | func testLoadInfoWrongSize() { | |
246 | // test what happens when a struct size is short | |
247 | ||
248 | let buffer = NSMutableData(capacity:1000)! | |
249 | ||
250 | var item = kcdata_item() | |
251 | ||
252 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
253 | item.flags = 0 | |
254 | item.size = 0 | |
255 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
256 | ||
257 | item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO) | |
258 | item.flags = 0 | |
259 | item.size = UInt32(sizeof(dyld_uuid_info_32)) - 1 | |
260 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
261 | ||
262 | let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")! | |
263 | ||
264 | var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid)) | |
265 | buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32) - 1) | |
266 | ||
267 | item.type = KCDATA_TYPE_BUFFER_END | |
268 | item.flags = 0 | |
269 | item.size = 0 | |
270 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
271 | ||
272 | guard let dict = try? self.parseBuffer(buffer) | |
273 | else { XCTFail(); return; } | |
274 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42) | |
275 | var uuidarray = nsuuid2array(uuid) | |
276 | uuidarray.removeLast() | |
277 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == uuidarray) | |
278 | } | |
279 | ||
280 | func testLoadInfoWayWrongSize() { | |
281 | // test what happens when a struct size is short | |
282 | ||
283 | let buffer = NSMutableData(capacity:1000)! | |
284 | ||
285 | var item = kcdata_item() | |
286 | ||
287 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
288 | item.flags = 0 | |
289 | item.size = 0 | |
290 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
291 | ||
292 | item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO) | |
293 | item.flags = 0 | |
294 | item.size = UInt32(sizeof(dyld_uuid_info_32)) - 16 | |
295 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
296 | ||
297 | let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")! | |
298 | ||
299 | var payload = dyld_uuid_info_32(imageLoadAddress: 42, imageUUID: nsuuid2uuid_t(uuid)) | |
300 | buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32) - 16) | |
301 | ||
302 | item.type = KCDATA_TYPE_BUFFER_END | |
303 | item.flags = 0 | |
304 | item.size = 0 | |
305 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
306 | ||
307 | guard let dict = try? self.parseBuffer(buffer) | |
308 | else { XCTFail(); return; } | |
309 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == 42) | |
310 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == nil) | |
311 | } | |
312 | ||
313 | func testLoadInfoPreposterousWrongSize() { | |
314 | // test what happens when a struct size is short | |
315 | ||
316 | let buffer = NSMutableData(capacity:1000)! | |
317 | ||
318 | var item = kcdata_item() | |
319 | ||
320 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
321 | item.flags = 0 | |
322 | item.size = 0 | |
323 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
324 | ||
325 | item.type = UInt32(KCDATA_TYPE_LIBRARY_LOADINFO) | |
326 | item.flags = 0 | |
327 | item.size = UInt32(1) | |
328 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
329 | ||
330 | var payload = UInt8(42) | |
331 | buffer.appendBytes(&payload, length:1) | |
332 | ||
333 | item.type = KCDATA_TYPE_BUFFER_END | |
334 | item.flags = 0 | |
335 | item.size = 0 | |
336 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
337 | ||
338 | guard let dict = try? self.parseBuffer(buffer) | |
339 | else { XCTFail(); return; } | |
340 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageLoadAddress"] == nil) | |
341 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??["imageUUID"] == nil) | |
342 | } | |
343 | ||
344 | ||
345 | func testNewArray(n : Int, pad : Int) { | |
346 | let buffer = NSMutableData(capacity:1000)! | |
347 | var item = kcdata_item() | |
348 | ||
349 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
350 | item.flags = 0 | |
351 | item.size = 0 | |
352 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
353 | ||
354 | item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0) + UInt32(pad) | |
355 | item.flags = UInt64(STACKSHOT_KCTYPE_DONATING_PIDS) << 32 | UInt64(n) | |
356 | item.size = UInt32(n * sizeof(UInt32) + pad) | |
357 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
358 | ||
359 | for i in 0..<n { | |
360 | var payload = UInt32(42 * i) | |
361 | buffer.appendBytes(&payload, length:sizeof(UInt32)) | |
362 | } | |
363 | ||
364 | for i in 0..<pad { | |
365 | var payload = UInt8(42-i) | |
366 | buffer.appendBytes(&payload, length:sizeof(UInt8)) | |
367 | } | |
368 | ||
369 | item.type = KCDATA_TYPE_BUFFER_END | |
370 | item.flags = 0 | |
371 | item.size = 0 | |
372 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
373 | ||
374 | guard let dict = try? self.parseBuffer(buffer) | |
375 | else { XCTFail(); return; } | |
376 | XCTAssert(dict["kcdata_crashinfo"]?["donating_pids"]??.count == n) | |
377 | for i in 0..<n { | |
378 | let x = dict["kcdata_crashinfo"] as? NSDictionary | |
379 | let y = x?["donating_pids"] as? NSArray | |
380 | XCTAssert((y?[i]) as? NSObject == 42 * i) | |
381 | } | |
382 | } | |
383 | ||
384 | func testNewArrays() { | |
385 | self.testNewArray(0,pad:0) | |
386 | for i in 1..<20 { | |
387 | for pad in 0..<16 { | |
388 | self.testNewArray(i, pad:pad) | |
389 | } | |
390 | } | |
391 | } | |
392 | ||
393 | ||
394 | func testArrayLoadInfo(n : Int) { | |
395 | let buffer = NSMutableData(capacity:1000)! | |
396 | var item = kcdata_item() | |
397 | ||
398 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
399 | item.flags = 0 | |
400 | item.size = 0 | |
401 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
402 | ||
403 | item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0) | |
404 | item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n) | |
405 | item.size = UInt32(n * sizeof(dyld_uuid_info_32)) | |
406 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
407 | ||
408 | let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")! | |
409 | ||
410 | ||
411 | for i in 0..<n { | |
412 | var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid)) | |
413 | ||
414 | buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32)) | |
415 | } | |
416 | ||
417 | item.type = KCDATA_TYPE_BUFFER_END | |
418 | item.flags = 0 | |
419 | item.size = 0 | |
420 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
421 | ||
422 | guard let dict = try? self.parseBuffer(buffer) | |
423 | else { XCTFail(); return; } | |
424 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n) | |
425 | for i in 0..<n { | |
426 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == 42+i) | |
427 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == nsuuid2array(uuid)) | |
428 | } | |
429 | } | |
430 | ||
431 | func testArrayLoadInfo() { | |
432 | for n in 0..<20 { | |
433 | testArrayLoadInfo(n) | |
434 | } | |
435 | } | |
436 | ||
437 | func testArrayLoadInfoWrongSize() { | |
438 | // test what happens when array element sizes are too short | |
439 | ||
440 | let n = 7 | |
441 | let wrong = 1 | |
442 | let buffer = NSMutableData(capacity:1000)! | |
443 | var item = kcdata_item() | |
444 | ||
445 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
446 | item.flags = 0 | |
447 | item.size = 0 | |
448 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
449 | ||
450 | item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0) | |
451 | item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n) | |
452 | item.size = UInt32(n * (sizeof(dyld_uuid_info_32) - wrong)) | |
453 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
454 | ||
455 | let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")! | |
456 | ||
457 | for i in 0..<n { | |
458 | var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid)) | |
459 | buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32)-wrong) | |
460 | } | |
461 | ||
462 | item.type = KCDATA_TYPE_BUFFER_END | |
463 | item.flags = 0 | |
464 | item.size = 0 | |
465 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
466 | ||
467 | var uuidarray = nsuuid2array(uuid) | |
468 | uuidarray.removeLast() | |
469 | ||
470 | guard let dict = try? self.parseBuffer(buffer) | |
471 | else { XCTFail(); return; } | |
472 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n) | |
473 | for i in 0..<n { | |
474 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == 42+i) | |
475 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == uuidarray) | |
476 | } | |
477 | } | |
478 | ||
479 | ||
480 | func testArrayLoadInfoWayWrongSize() { | |
481 | // test what happens when array element sizes are too short | |
482 | ||
483 | let n = 7 | |
484 | let wrong = 16 | |
485 | let buffer = NSMutableData(capacity:1000)! | |
486 | var item = kcdata_item() | |
487 | ||
488 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
489 | item.flags = 0 | |
490 | item.size = 0 | |
491 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
492 | ||
493 | item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0) | |
494 | item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n) | |
495 | item.size = UInt32(n * (sizeof(dyld_uuid_info_32) - wrong)) | |
496 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
497 | ||
498 | let uuid = NSUUID(UUIDString: "de305d54-75b4-431b-adb2-eb6b9e546014")! | |
499 | ||
500 | for i in 0..<n { | |
501 | var payload = dyld_uuid_info_32(imageLoadAddress:UInt32(i+42), imageUUID: nsuuid2uuid_t(uuid)) | |
502 | buffer.appendBytes(&payload, length:sizeof(dyld_uuid_info_32)-wrong) | |
503 | } | |
504 | ||
505 | item.type = KCDATA_TYPE_BUFFER_END | |
506 | item.flags = 0 | |
507 | item.size = 0 | |
508 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
509 | ||
510 | guard let dict = try? self.parseBuffer(buffer) | |
511 | else { XCTFail(); return; } | |
512 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n) | |
513 | for i in 0..<n { | |
514 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == 42+i) | |
515 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == nil) | |
516 | } | |
517 | } | |
518 | ||
519 | func testArrayLoadInfoPreposterouslyWrongSize() { | |
520 | // test what happens when array element sizes are too short | |
521 | ||
522 | let n = 7 | |
523 | let wrong = 19 | |
524 | let buffer = NSMutableData(capacity:1000)! | |
525 | var item = kcdata_item() | |
526 | ||
527 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
528 | item.flags = 0 | |
529 | item.size = 0 | |
530 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
531 | ||
532 | item.type = UInt32(KCDATA_TYPE_ARRAY_PAD0) | |
533 | item.flags = UInt64(KCDATA_TYPE_LIBRARY_LOADINFO) << 32 | UInt64(n) | |
534 | item.size = UInt32(n * (sizeof(dyld_uuid_info_32) - wrong)) | |
535 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
536 | ||
537 | for i in 0..<n { | |
538 | var payload = UInt8(42*i) | |
539 | buffer.appendBytes(&payload, length:1) | |
540 | } | |
541 | ||
542 | item.type = KCDATA_TYPE_BUFFER_END | |
543 | item.flags = 0 | |
544 | item.size = 0 | |
545 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
546 | ||
547 | guard let dict = try? self.parseBuffer(buffer) | |
548 | else { XCTFail(); return; } | |
549 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??.count == n) | |
550 | for i in 0..<n { | |
551 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageLoadAddress"] == nil) | |
552 | XCTAssert(dict["kcdata_crashinfo"]?["dyld_load_info"]??[i]?["imageUUID"] == nil) | |
553 | } | |
554 | } | |
555 | ||
556 | ||
557 | func testNested() { | |
558 | let buffer = NSMutableData(capacity:1000)! | |
559 | ||
560 | var item = kcdata_item() | |
561 | ||
562 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
563 | item.flags = 0 | |
564 | item.size = 0 | |
565 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
566 | ||
567 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
568 | item.flags = 0 | |
569 | item.size = UInt32(sizeof(UInt64)) | |
570 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
571 | ||
572 | var payload : UInt64 = 42 | |
573 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
574 | ||
575 | item.type = KCDATA_TYPE_BUFFER_END | |
576 | item.flags = 0 | |
577 | item.size = 0 | |
578 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
579 | ||
580 | let buffer2 = NSMutableData(capacity:1000)! | |
581 | ||
582 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
583 | item.flags = 0 | |
584 | item.size = 0 | |
585 | buffer2.appendBytes(&item, length: sizeof(kcdata_item)) | |
586 | ||
587 | item.type = UInt32(KCDATA_TYPE_NESTED_KCDATA) | |
588 | item.flags = 0 | |
589 | item.size = UInt32(buffer.length) | |
590 | buffer2.appendBytes(&item, length: sizeof(kcdata_item)) | |
591 | buffer2.appendData(buffer) | |
592 | ||
593 | item.type = KCDATA_TYPE_BUFFER_END | |
594 | item.flags = 0 | |
595 | item.size = 0 | |
596 | buffer2.appendBytes(&item, length: sizeof(kcdata_item)) | |
597 | ||
598 | guard let dict2 = try? self.parseBuffer(buffer2) | |
599 | else { XCTFail(); return; } | |
600 | ||
601 | XCTAssert(dict2["kcdata_crashinfo"]?["kcdata_crashinfo"]??["crashed_threadid"] == 42) | |
602 | } | |
603 | ||
604 | ||
605 | func testReadThreadid() { | |
606 | let buffer = NSMutableData(capacity:1000)! | |
607 | ||
608 | var item = kcdata_item() | |
609 | ||
610 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
611 | item.flags = 0 | |
612 | item.size = 0 | |
613 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
614 | ||
615 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
616 | item.flags = 0 | |
617 | item.size = UInt32(sizeof(UInt64)) | |
618 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
619 | ||
620 | var payload : UInt64 = 42 | |
621 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
622 | ||
623 | item.type = KCDATA_TYPE_BUFFER_END | |
624 | item.flags = 0 | |
625 | item.size = 0 | |
626 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
627 | ||
628 | guard let dict = try? self.parseBuffer(buffer) | |
629 | else { XCTFail(); return; } | |
630 | ||
631 | XCTAssert(dict["kcdata_crashinfo"]!["crashed_threadid"] == 42) | |
632 | } | |
633 | ||
634 | ||
635 | func testRepeatedKey() { | |
636 | // test a repeated item of the same key causes error | |
637 | ||
638 | let buffer = NSMutableData(capacity:1000)! | |
639 | ||
640 | var item = kcdata_item() | |
641 | ||
642 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
643 | item.flags = 0 | |
644 | item.size = 0 | |
645 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
646 | ||
647 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
648 | item.flags = 0 | |
649 | item.size = UInt32(sizeof(UInt64)) | |
650 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
651 | ||
652 | var payload : UInt64 = 42 | |
653 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
654 | ||
655 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
656 | item.flags = 0 | |
657 | item.size = UInt32(sizeof(UInt64)) | |
658 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
659 | ||
660 | payload = 42 | |
661 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
662 | ||
663 | item.type = KCDATA_TYPE_BUFFER_END | |
664 | item.flags = 0 | |
665 | item.size = 0 | |
666 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
667 | ||
668 | XCTAssert( (try? self.parseBuffer(buffer)) == nil ) | |
669 | } | |
670 | ||
671 | ||
672 | func testContainer() { | |
673 | let buffer = NSMutableData(capacity:1000)! | |
674 | ||
675 | var item = kcdata_item() | |
676 | var payload64 : UInt64 | |
677 | var payload32 : UInt32 | |
678 | ||
679 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
680 | item.flags = 0 | |
681 | item.size = 0 | |
682 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
683 | ||
684 | item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN) | |
685 | item.flags = 0 | |
686 | item.size = UInt32(sizeof(UInt32)) | |
687 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
688 | payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK) | |
689 | buffer.appendBytes(&payload32, length:sizeof(UInt32)) | |
690 | ||
691 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
692 | item.flags = 0 | |
693 | item.size = UInt32(sizeof(UInt64)) | |
694 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
695 | payload64 = 42 | |
696 | buffer.appendBytes(&payload64, length:sizeof(UInt64)) | |
697 | ||
698 | item.type = UInt32(KCDATA_TYPE_CONTAINER_END) | |
699 | item.flags = 0 | |
700 | item.size = UInt32(sizeof(UInt32)) | |
701 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
702 | payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK) | |
703 | buffer.appendBytes(&payload32, length:sizeof(UInt32)) | |
704 | ||
705 | ||
706 | item.type = KCDATA_TYPE_BUFFER_END | |
707 | item.flags = 0 | |
708 | item.size = 0 | |
709 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
710 | ||
711 | guard let dict = try? self.parseBuffer(buffer) | |
712 | else { XCTFail(); return; } | |
713 | ||
714 | XCTAssert(dict["kcdata_crashinfo"]?["task_snapshots"]??["0"]??["crashed_threadid"] == 42) | |
715 | ||
716 | } | |
717 | ||
718 | func testRepeatedContainer() { | |
719 | //repeated container of same name and key shoudl fail | |
720 | ||
721 | let buffer = NSMutableData(capacity:1000)! | |
722 | ||
723 | var item = kcdata_item() | |
724 | var payload64 : UInt64 | |
725 | var payload32 : UInt32 | |
726 | ||
727 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
728 | item.flags = 0 | |
729 | item.size = 0 | |
730 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
731 | ||
732 | item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN) | |
733 | item.flags = 0 | |
734 | item.size = UInt32(sizeof(UInt32)) | |
735 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
736 | payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK) | |
737 | buffer.appendBytes(&payload32, length:sizeof(UInt32)) | |
738 | ||
739 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
740 | item.flags = 0 | |
741 | item.size = UInt32(sizeof(UInt64)) | |
742 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
743 | payload64 = 42 | |
744 | buffer.appendBytes(&payload64, length:sizeof(UInt64)) | |
745 | ||
746 | item.type = UInt32(KCDATA_TYPE_CONTAINER_END) | |
747 | item.flags = 0 | |
748 | item.size = UInt32(sizeof(UInt32)) | |
749 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
750 | payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK) | |
751 | buffer.appendBytes(&payload32, length:sizeof(UInt32)) | |
752 | ||
753 | ||
754 | item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN) | |
755 | item.flags = 0 | |
756 | item.size = UInt32(sizeof(UInt32)) | |
757 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
758 | payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK) | |
759 | buffer.appendBytes(&payload32, length:sizeof(UInt32)) | |
760 | ||
761 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
762 | item.flags = 0 | |
763 | item.size = UInt32(sizeof(UInt64)) | |
764 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
765 | payload64 = 42 | |
766 | buffer.appendBytes(&payload64, length:sizeof(UInt64)) | |
767 | ||
768 | item.type = UInt32(KCDATA_TYPE_CONTAINER_END) | |
769 | item.flags = 0 | |
770 | item.size = UInt32(sizeof(UInt32)) | |
771 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
772 | payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK) | |
773 | buffer.appendBytes(&payload32, length:sizeof(UInt32)) | |
774 | ||
775 | item.type = KCDATA_TYPE_BUFFER_END | |
776 | item.flags = 0 | |
777 | item.size = 0 | |
778 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
779 | ||
780 | XCTAssert( (try? self.parseBuffer(buffer)) == nil ) | |
781 | } | |
782 | ||
783 | ||
784 | func testContainerNoEnd() { | |
785 | let buffer = NSMutableData(capacity:1000)! | |
786 | ||
787 | var item = kcdata_item() | |
788 | var payload64 : UInt64 | |
789 | var payload32 : UInt32 | |
790 | ||
791 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
792 | item.flags = 0 | |
793 | item.size = 0 | |
794 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
795 | ||
796 | item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN) | |
797 | item.flags = 0 | |
798 | item.size = UInt32(sizeof(UInt32)) | |
799 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
800 | payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK) | |
801 | buffer.appendBytes(&payload32, length:sizeof(UInt32)) | |
802 | ||
803 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
804 | item.flags = 0 | |
805 | item.size = UInt32(sizeof(UInt64)) | |
806 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
807 | payload64 = 42 | |
808 | buffer.appendBytes(&payload64, length:sizeof(UInt64)) | |
809 | ||
810 | item.type = KCDATA_TYPE_BUFFER_END | |
811 | item.flags = 0 | |
812 | item.size = 0 | |
813 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
814 | ||
815 | XCTAssert( (try? self.parseBuffer(buffer)) == nil ) | |
816 | } | |
817 | ||
818 | func testContainerNoEndNoEnd() { | |
819 | let buffer = NSMutableData(capacity:1000)! | |
820 | ||
821 | var item = kcdata_item() | |
822 | var payload64 : UInt64 | |
823 | var payload32 : UInt32 | |
824 | ||
825 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
826 | item.flags = 0 | |
827 | item.size = 0 | |
828 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
829 | ||
830 | item.type = UInt32(KCDATA_TYPE_CONTAINER_BEGIN) | |
831 | item.flags = 0 | |
832 | item.size = UInt32(sizeof(UInt32)) | |
833 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
834 | payload32 = UInt32(STACKSHOT_KCCONTAINER_TASK) | |
835 | buffer.appendBytes(&payload32, length:sizeof(UInt32)) | |
836 | ||
837 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
838 | item.flags = 0 | |
839 | item.size = UInt32(sizeof(UInt64)) | |
840 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
841 | payload64 = 42 | |
842 | buffer.appendBytes(&payload64, length:sizeof(UInt64)) | |
843 | ||
844 | XCTAssert( (try? self.parseBuffer(buffer)) == nil ) | |
845 | } | |
846 | ||
847 | ||
848 | ||
849 | func testNoEnd() { | |
850 | let buffer = NSMutableData(capacity:1000)! | |
851 | ||
852 | var item = kcdata_item() | |
853 | ||
854 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
855 | item.flags = 0 | |
856 | item.size = 0 | |
857 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
858 | ||
859 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
860 | item.flags = 0 | |
861 | item.size = UInt32(sizeof(UInt64)) | |
862 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
863 | ||
864 | var payload : UInt64 = 42 | |
865 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
866 | ||
867 | XCTAssert( (try? self.parseBuffer(buffer)) == nil ) | |
868 | } | |
869 | ||
870 | ||
871 | func testCrazySize() { | |
872 | let buffer = NSMutableData(capacity:1000)! | |
873 | ||
874 | var item = kcdata_item() | |
875 | ||
876 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
877 | item.flags = 0 | |
878 | item.size = 0 | |
879 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
880 | ||
881 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
882 | item.flags = 0 | |
883 | item.size = 99999 | |
884 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
885 | ||
886 | var payload : UInt64 = 42 | |
887 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
888 | ||
889 | item.type = KCDATA_TYPE_BUFFER_END | |
890 | item.flags = 0 | |
891 | item.size = 0 | |
892 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
893 | ||
894 | XCTAssert( (try? self.parseBuffer(buffer)) == nil ) | |
895 | } | |
896 | ||
897 | func testReadRepeatedArray() { | |
898 | // repeated arrays should be concatenated | |
899 | let n = 10 | |
900 | ||
901 | let buffer = NSMutableData(capacity:1000)! | |
902 | ||
903 | var item = kcdata_item() | |
904 | ||
905 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
906 | item.flags = 0 | |
907 | item.size = 0 | |
908 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
909 | ||
910 | item.type = UInt32(KCDATA_TYPE_ARRAY) | |
911 | item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n) | |
912 | item.size = UInt32(n * sizeof(UInt64)) | |
913 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
914 | ||
915 | for i in 0..<n { | |
916 | var payload : UInt64 = UInt64(i) | |
917 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
918 | } | |
919 | ||
920 | item.type = UInt32(KCDATA_TYPE_ARRAY) | |
921 | item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n) | |
922 | item.size = UInt32(n * sizeof(UInt64)) | |
923 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
924 | ||
925 | for i in 0..<n { | |
926 | var payload : UInt64 = UInt64(i) | |
927 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
928 | } | |
929 | ||
930 | item.type = KCDATA_TYPE_BUFFER_END | |
931 | item.flags = 0 | |
932 | item.size = 0 | |
933 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
934 | ||
935 | guard let dict = try? self.parseBuffer(buffer) | |
936 | else { XCTFail(); return } | |
937 | ||
938 | XCTAssert( 2*n == dict["kcdata_crashinfo"]!["crashed_threadid"]!!.count) | |
939 | for i in 0..<2*n { | |
940 | let x = dict["kcdata_crashinfo"] as? NSDictionary | |
941 | let y = x?["crashed_threadid"] as? NSArray | |
942 | XCTAssert((y?[i]) as? NSObject == i % n) | |
943 | } | |
944 | } | |
945 | ||
946 | func testReadThreadidArray(n : Int, pad : Int) { | |
947 | let buffer = NSMutableData(capacity:1000)! | |
948 | ||
949 | var item = kcdata_item() | |
950 | ||
951 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
952 | item.flags = 0 | |
953 | item.size = 0 | |
954 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
955 | ||
956 | item.type = UInt32(KCDATA_TYPE_ARRAY) | |
957 | item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n) | |
958 | item.size = UInt32(n * sizeof(UInt64) + pad) | |
959 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
960 | ||
961 | for i in 0..<n { | |
962 | var payload : UInt64 = UInt64(i) | |
963 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
964 | } | |
965 | ||
966 | for _ in 0..<pad { | |
967 | var payload : UInt8 = 0 | |
968 | buffer.appendBytes(&payload, length:1) | |
969 | } | |
970 | ||
971 | item.type = KCDATA_TYPE_BUFFER_END | |
972 | item.flags = 0 | |
973 | item.size = 0 | |
974 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
975 | ||
976 | guard let dict = try? self.parseBuffer(buffer) | |
977 | else { XCTFail(); return; } | |
978 | ||
979 | XCTAssert( n == dict["kcdata_crashinfo"]?["crashed_threadid"]??.count) | |
980 | for i in 0..<n { | |
981 | let x = dict["kcdata_crashinfo"] as? NSDictionary | |
982 | let y = x?["crashed_threadid"] as? NSArray | |
983 | XCTAssert((y?[i]) as? NSObject == i) | |
984 | } | |
985 | ||
986 | } | |
987 | ||
988 | func testReadThreadidArray() { | |
989 | // test that we can correctly read old arrays with a variety of sizes and paddings | |
990 | self.testReadThreadidArray(0, pad:0) | |
991 | for n in 1..<100 { | |
992 | for pad in 0..<16 { | |
993 | self.testReadThreadidArray(n, pad:pad) | |
994 | } | |
995 | } | |
996 | } | |
997 | ||
998 | func testReadThreadidArrayWrongSize1() { | |
999 | /// for old style arrays, if the element size is determined by the type. If the array of that size element at the given count doesn't fit, then parsing should fail | |
1000 | ||
1001 | let n = 1 | |
1002 | ||
1003 | let buffer = NSMutableData(capacity:1000)! | |
1004 | ||
1005 | var item = kcdata_item() | |
1006 | ||
1007 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
1008 | item.flags = 0 | |
1009 | item.size = 0 | |
1010 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1011 | ||
1012 | item.type = UInt32(KCDATA_TYPE_ARRAY) | |
1013 | item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n) | |
1014 | item.size = UInt32(4) | |
1015 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1016 | ||
1017 | var payload : UInt32 = UInt32(42) | |
1018 | buffer.appendBytes(&payload, length:sizeof(UInt32)) | |
1019 | ||
1020 | item.type = KCDATA_TYPE_BUFFER_END | |
1021 | item.flags = 0 | |
1022 | item.size = 0 | |
1023 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1024 | ||
1025 | XCTAssert( (try? self.parseBuffer(buffer)) == nil ) | |
1026 | } | |
1027 | ||
1028 | func testReadThreadidArrayWrongSize5() { | |
1029 | /// if the count is bigger than the buffer, parsing will just fail | |
1030 | ||
1031 | let n = 5 | |
1032 | ||
1033 | let buffer = NSMutableData(capacity:1000)! | |
1034 | ||
1035 | var item = kcdata_item() | |
1036 | ||
1037 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
1038 | item.flags = 0 | |
1039 | item.size = 0 | |
1040 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1041 | ||
1042 | item.type = UInt32(KCDATA_TYPE_ARRAY) | |
1043 | item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n) | |
1044 | item.size = UInt32(4) | |
1045 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1046 | ||
1047 | var payload : UInt32 = UInt32(42) | |
1048 | buffer.appendBytes(&payload, length:sizeof(UInt32)) | |
1049 | ||
1050 | item.type = KCDATA_TYPE_BUFFER_END | |
1051 | item.flags = 0 | |
1052 | item.size = 0 | |
1053 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1054 | ||
1055 | XCTAssert( (try? self.parseBuffer(buffer)) == nil ) | |
1056 | } | |
1057 | ||
1058 | ||
1059 | func testReadThreadidArrayPaddedSize() { | |
1060 | // test that we can tolerate a little padding at the end of an array | |
1061 | let n = 5 | |
1062 | ||
1063 | let buffer = NSMutableData(capacity:1000)! | |
1064 | ||
1065 | var item = kcdata_item() | |
1066 | ||
1067 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
1068 | item.flags = 0 | |
1069 | item.size = 0 | |
1070 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1071 | ||
1072 | item.type = UInt32(KCDATA_TYPE_ARRAY) | |
1073 | item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n) | |
1074 | item.size = UInt32(n * sizeof(UInt64)) + 1 | |
1075 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1076 | ||
1077 | for i in 0..<n { | |
1078 | var payload : UInt64 = UInt64(i) | |
1079 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
1080 | } | |
1081 | var payload : UInt8 = 0 | |
1082 | buffer.appendBytes(&payload, length:1) | |
1083 | ||
1084 | item.type = KCDATA_TYPE_BUFFER_END | |
1085 | item.flags = 0 | |
1086 | item.size = 0 | |
1087 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1088 | ||
1089 | guard let dict = try? self.parseBuffer(buffer) | |
1090 | else { XCTFail(); return; } | |
1091 | ||
1092 | XCTAssert( n == dict["kcdata_crashinfo"]?["crashed_threadid"]??.count) | |
1093 | for i in 0..<n { | |
1094 | let x = dict["kcdata_crashinfo"] as? NSDictionary | |
1095 | let y = x?["crashed_threadid"] as? NSArray | |
1096 | XCTAssert((y?[i]) as? NSObject == i) | |
1097 | } | |
1098 | } | |
1099 | ||
1100 | func testReadThreadidArrayPaddedSize15() { | |
1101 | // test that we can tolerate a little padding at the end of an array | |
1102 | let n = 5 | |
1103 | ||
1104 | let buffer = NSMutableData(capacity:1000)! | |
1105 | ||
1106 | var item = kcdata_item() | |
1107 | ||
1108 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
1109 | item.flags = 0 | |
1110 | item.size = 0 | |
1111 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1112 | ||
1113 | item.type = UInt32(KCDATA_TYPE_ARRAY) | |
1114 | item.flags = UInt64(TASK_CRASHINFO_CRASHED_THREADID) << 32 | UInt64(n) | |
1115 | item.size = UInt32(n * sizeof(UInt64)) + 15 | |
1116 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1117 | ||
1118 | for i in 0..<n { | |
1119 | var payload : UInt64 = UInt64(i) | |
1120 | buffer.appendBytes(&payload, length:sizeof(UInt64)) | |
1121 | } | |
1122 | for i in 0..<15 { | |
1123 | i; | |
1124 | var payload : UInt8 = 0 | |
1125 | buffer.appendBytes(&payload, length:1) | |
1126 | } | |
1127 | ||
1128 | item.type = KCDATA_TYPE_BUFFER_END | |
1129 | item.flags = 0 | |
1130 | item.size = 0 | |
1131 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1132 | ||
1133 | guard let dict = try? self.parseBuffer(buffer) | |
1134 | else { XCTFail(); return; } | |
1135 | ||
1136 | XCTAssert( n == dict["kcdata_crashinfo"]?["crashed_threadid"]??.count) | |
1137 | for i in 0..<n { | |
1138 | let x = dict["kcdata_crashinfo"] as? NSDictionary | |
1139 | let y = x?["crashed_threadid"] as? NSArray | |
1140 | XCTAssert((y?[i]) as? NSObject == i) | |
1141 | } | |
1142 | } | |
1143 | ||
1144 | ||
1145 | func testReadThreadidWrongSize(size : UInt32) { | |
1146 | let buffer = NSMutableData(capacity:1000)! | |
1147 | ||
1148 | var item = kcdata_item() | |
1149 | ||
1150 | item.type = KCDATA_BUFFER_BEGIN_CRASHINFO | |
1151 | item.flags = 0 | |
1152 | item.size = 0 | |
1153 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1154 | ||
1155 | item.type = UInt32(TASK_CRASHINFO_CRASHED_THREADID) | |
1156 | item.flags = 0 | |
1157 | item.size = size | |
1158 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1159 | ||
1160 | var payload : UInt64 = 42 | |
1161 | buffer.appendBytes(&payload, length:Int(size)) | |
1162 | ||
1163 | item.type = KCDATA_TYPE_BUFFER_END | |
1164 | item.flags = 0 | |
1165 | item.size = 0 | |
1166 | buffer.appendBytes(&item, length: sizeof(kcdata_item)) | |
1167 | ||
1168 | guard let dict = try? self.parseBuffer(buffer) | |
1169 | else { XCTFail(); return; } | |
1170 | ||
1171 | XCTAssert(dict["kcdata_crashinfo"]?["crashed_threadid"] == nil) | |
1172 | } | |
1173 | ||
1174 | func testReadThreadidWrongSize0() { | |
1175 | self.testReadThreadidWrongSize(0) | |
1176 | } | |
1177 | ||
1178 | func testReadThreadidWrongSize7() { | |
1179 | self.testReadThreadidWrongSize(7) | |
1180 | } | |
1181 | ||
1182 | func dataWithResource(name:String) -> NSData? { | |
1183 | guard let filename = NSBundle(forClass: self.classForCoder).pathForResource(name, ofType: nil) | |
1184 | else { return nil } | |
1185 | return NSData(contentsOfFile:filename)! | |
1186 | } | |
1187 | ||
1188 | func testSampleStackshot(name : String) { | |
1189 | // check that we agree with sample file | |
1190 | ||
1191 | guard let sampledata = self.dataWithResource(name) | |
1192 | else { XCTFail(); return } | |
1193 | var dict : NSDictionary? | |
1194 | ||
1195 | dict = try? self.parseBuffer(sampledata) | |
1196 | ||
1197 | if (dict == nil) { | |
1198 | if let decoded = NSData(base64EncodedData: sampledata, options:.IgnoreUnknownCharacters) { | |
1199 | dict = try? self.parseBuffer(decoded) | |
1200 | } | |
1201 | } | |
1202 | ||
1203 | if (dict == nil) { | |
1204 | if let decompressed = try? decompress(sampledata) { | |
1205 | dict = try? self.parseBuffer(decompressed) | |
1206 | } | |
1207 | } | |
1208 | ||
1209 | if (dict == nil) { | |
1210 | XCTFail(); return; | |
1211 | } | |
1212 | ||
1213 | guard let plistdata = self.dataWithResource(name + ".plist.gz") ?? | |
1214 | self.dataWithResource(name + ".plist") | |
1215 | else {XCTFail(); return} | |
1216 | ||
1217 | var dict2 = try? NSPropertyListSerialization.propertyListWithData(plistdata, options: NSPropertyListReadOptions.Immutable, format: nil) | |
1218 | if dict2 == nil { | |
1219 | dict2 = try? NSPropertyListSerialization.propertyListWithData(decompress(plistdata), options: .Immutable, format: nil) | |
1220 | } | |
1221 | ||
1222 | XCTAssert(dict2 != nil) | |
1223 | ||
1224 | XCTAssert(dict == dict2 as? NSDictionary) | |
1225 | ||
1226 | // check that we agree with python | |
1227 | ||
1228 | #if os(OSX) | |
1229 | ||
1230 | let kcdatapy = NSBundle(forClass: self.classForCoder).pathForResource("kcdata.py", ofType: nil) | |
1231 | ||
1232 | let task = NSTask() | |
1233 | task.launchPath = kcdatapy | |
1234 | task.arguments = ["-p", | |
1235 | NSBundle(forClass:self.classForCoder).pathForResource(name, ofType: nil)!] | |
1236 | let pipe = NSPipe() | |
1237 | task.standardOutput = pipe | |
1238 | task.launch() | |
1239 | ||
1240 | let data = pipe.fileHandleForReading.readDataToEndOfFile() | |
1241 | ||
1242 | guard let dict3 = try? NSPropertyListSerialization.propertyListWithData(data, options: .Immutable, format: nil) as? NSDictionary | |
1243 | else { XCTFail(); return } | |
1244 | ||
1245 | XCTAssert(dict == dict3) | |
1246 | ||
1247 | #endif | |
1248 | } | |
1249 | ||
1250 | func testSampleStackshot() { | |
1251 | self.testSampleStackshot("stackshot-sample") | |
1252 | } | |
1253 | ||
1254 | func testSampleStackshotOldArrays() { | |
1255 | self.testSampleStackshot("stackshot-sample-old-arrays") | |
1256 | } | |
1257 | ||
1258 | func testSampleStackshotNewArrays() { | |
1259 | self.testSampleStackshot("stackshot-sample-new-arrays") | |
1260 | } | |
1261 | ||
1262 | func testSampleDeltaStackshotOldArrays() { | |
1263 | self.testSampleStackshot("delta-stackshot-sample-old-arrays") | |
1264 | } | |
1265 | ||
1266 | func testSampleDeltaStackshotNewArrays() { | |
1267 | self.testSampleStackshot("delta-stackshot-sample-new-arrays") | |
1268 | } | |
1269 | ||
1270 | func testSampleCorpse() { | |
1271 | self.testSampleStackshot("corpse-sample") | |
1272 | } | |
1273 | ||
1274 | func testSampleStackshotTailspin() { | |
1275 | self.testSampleStackshot("stackshot-sample-tailspin") | |
1276 | } | |
1277 | ||
1278 | func testSampleStackshotTailspin2() { | |
1279 | self.testSampleStackshot("stackshot-sample-tailspin-2") | |
1280 | } | |
1281 | ||
1282 | func testSampleExitReason() { | |
1283 | self.testSampleStackshot("exitreason-sample") | |
1284 | } | |
1285 | ||
1286 | func testSampleThreadT() { | |
1287 | self.testSampleStackshot("stackshot-sample-ths-thread-t") | |
1288 | } | |
1289 | ||
1290 | func testSampleCpuTimes() { | |
1291 | self.testSampleStackshot("stackshot-sample-cputime") | |
1292 | } | |
1293 | ||
1294 | func testSampleDuration() { | |
1295 | self.testSampleStackshot("stackshot-sample-duration") | |
1296 | } | |
1297 | ||
1298 | func testSampleNested() { | |
1299 | self.testSampleStackshot("nested-sample") | |
1300 | } | |
1301 | ||
1302 | func testSampleTermWithReason() { | |
1303 | self.testSampleStackshot("test-twr-sample") | |
1304 | } | |
1305 | ||
1306 | func testSampleCorpseTermWithReason() { | |
1307 | self.testSampleStackshot("corpse-twr-sample") | |
1308 | } | |
1309 | ||
1310 | func testSampleCorpseTermWithReasonV2() { | |
1311 | self.testSampleStackshot("corpse-twr-sample-v2") | |
1312 | } | |
1313 | ||
1314 | func testSampleCodesigningExitReason() { | |
1315 | self.testSampleStackshot("exitreason-codesigning") | |
1316 | } | |
1317 | ||
1318 | func testStackshotSharedcacheV2() { | |
1319 | self.testSampleStackshot("stackshot-sample-sharedcachev2") | |
1320 | } | |
1321 | ||
1322 | func testStackshotFaultStats() { | |
1323 | self.testSampleStackshot("stackshot-fault-stats") | |
1324 | } | |
1325 | ||
1326 | func testStackshotwithKCID() { | |
1327 | self.testSampleStackshot("stackshot-with-kcid") | |
1328 | } | |
1329 | ||
1330 | func testXNUPostTestConfig() { | |
1331 | self.testSampleStackshot("xnupost_testconfig-sample") | |
1332 | } | |
1333 | ||
1334 | func testTrivial() { | |
1335 | } | |
1336 | } |