ios: Update XCUITests to check various crash type exception codes.

Bug: crashpad:31
Change-Id: I804def3be0050b3e6f15d7d77d0b70184c380673
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3087722
Commit-Queue: Justin Cohen <justincohen@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Justin Cohen 2021-10-28 17:02:27 -04:00 committed by Crashpad LUCI CQ
parent 15c4663b8c
commit fad3bdcde0
7 changed files with 402 additions and 180 deletions

View File

@ -244,10 +244,10 @@ crashpad_static_library("snapshot") {
public_deps = [ ":context" ]
deps = [
"$mini_chromium_source_parent:base",
"../client:common",
"../compat",
"../minidump:format",
"$mini_chromium_source_parent:base",
"../util",
]
@ -318,8 +318,8 @@ static_library("test_support") {
public_deps = [ ":snapshot" ]
deps = [
"../compat",
"$mini_chromium_source_parent:base",
"../compat",
"../util",
]
@ -429,13 +429,13 @@ source_set("snapshot_test") {
deps = [
":test_support",
"$mini_chromium_source_parent:base",
"../client:common",
"../compat",
"../minidump:format",
"../test",
"../third_party/googletest:googlemock",
"../third_party/googletest:googletest",
"$mini_chromium_source_parent:base",
"../util",
]
@ -489,8 +489,8 @@ crashpad_loadable_module("crashpad_snapshot_test_module") {
testonly = true
sources = [ "crashpad_info_client_options_test_module.cc" ]
deps = [
"../client",
"$mini_chromium_source_parent:base",
"../client",
]
}
@ -533,7 +533,7 @@ if ((crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) &&
}
}
if (crashpad_is_mac) {
if (crashpad_is_mac || crashpad_is_ios) {
crashpad_loadable_module("crashpad_snapshot_test_module_crashy_initializer") {
testonly = true
sources = [
@ -552,9 +552,9 @@ if (crashpad_is_win) {
testonly = true
sources = [ "win/crashpad_snapshot_test_annotations.cc" ]
deps = [
"$mini_chromium_source_parent:base",
"../client",
"../compat",
"$mini_chromium_source_parent:base",
]
}
@ -562,9 +562,9 @@ if (crashpad_is_win) {
testonly = true
sources = [ "win/crashpad_snapshot_test_crashing_child.cc" ]
deps = [
"$mini_chromium_source_parent:base",
"../client",
"../compat",
"$mini_chromium_source_parent:base",
"../util",
]
}
@ -573,9 +573,9 @@ if (crashpad_is_win) {
testonly = true
sources = [ "win/crashpad_snapshot_test_dump_without_crashing.cc" ]
deps = [
"$mini_chromium_source_parent:base",
"../client",
"../compat",
"$mini_chromium_source_parent:base",
"../util",
]
}
@ -584,9 +584,9 @@ if (crashpad_is_win) {
testonly = true
sources = [ "win/crashpad_snapshot_test_extra_memory_ranges.cc" ]
deps = [
"$mini_chromium_source_parent:base",
"../client",
"../compat",
"$mini_chromium_source_parent:base",
]
}
@ -594,9 +594,9 @@ if (crashpad_is_win) {
testonly = true
sources = [ "win/crashpad_snapshot_test_image_reader.cc" ]
deps = [
"$mini_chromium_source_parent:base",
"../client",
"../compat",
"$mini_chromium_source_parent:base",
"../util",
]
if (crashpad_is_in_chromium) {
@ -613,8 +613,8 @@ if (crashpad_is_win) {
testonly = true
sources = [ "win/crashpad_snapshot_test_image_reader_module.cc" ]
deps = [
"../client",
"$mini_chromium_source_parent:base",
"../client",
]
if (crashpad_is_in_chromium) {
if (symbol_level == 0) {

View File

@ -72,6 +72,7 @@ source_set("xcuitests") {
"../../build:ios_xctest",
"../../test/ios/host:app_shared_sources",
"../../third_party/edo",
"../../util",
]
}

View File

@ -13,38 +13,34 @@
// limitations under the License.
#import <XCTest/XCTest.h>
#include <objc/runtime.h>
#import "Service/Sources/EDOClientService.h"
#import "test/ios/host/cptest_shared_object.h"
#include "util/mach/exception_types.h"
#include "util/mach/mach_extensions.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface CPTestTestCase : XCTestCase {
XCUIApplication* _app;
XCUIApplication* app_;
CPTestSharedObject* rootObject_;
}
@end
@implementation CPTestTestCase
- (void)handleCrashUnderSymbol:(id)arg1 {
// For now, do nothing. In the future this can be something testable.
}
+ (void)setUp {
// Swizzle away the handleCrashUnderSymbol callback. Without this, any time
// the host app is intentionally crashed, the test is immediately failed.
SEL originalSelector = NSSelectorFromString(@"handleCrashUnderSymbol:");
SEL swizzledSelector = @selector(handleCrashUnderSymbol:);
Method originalMethod = class_getInstanceMethod(
objc_getClass("XCUIApplicationImpl"), originalSelector);
Method swizzledMethod =
class_getInstanceMethod([self class], swizzledSelector);
method_exchangeImplementations(originalMethod, swizzledMethod);
// Override EDO default error handler. Without this, the default EDO error
@ -54,188 +50,186 @@
});
}
// This gets called after tearDown, so there's no straightforward way to
// test that this is called. However, not swizzling this out will cause every
// crashing test to fail.
- (void)handleCrashUnderSymbol:(id)arg1 {
}
- (void)setUp {
_app = [[XCUIApplication alloc] init];
[_app launch];
app_ = [[XCUIApplication alloc] init];
[app_ launch];
rootObject_ = [EDOClientService rootObjectWithPort:12345];
[rootObject_ clearPendingReports];
XCTAssertEqual([rootObject_ pendingReportCount], 0);
XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground);
}
- (void)verifyCrashReportException:(int)exception {
// Confirm the app is not running.
XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning);
// Restart app to get the report signal.
[app_ launch];
XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground);
rootObject_ = [EDOClientService rootObjectWithPort:12345];
XCTAssertEqual([rootObject_ pendingReportCount], 1);
XCTAssertEqual([rootObject_ pendingReportException], exception);
}
- (void)testEDO {
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
NSString* result = [rootObject testEDO];
NSString* result = [rootObject_ testEDO];
XCTAssertEqualObjects(result, @"crashpad");
}
- (void)testSegv {
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
// Crash the app.
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
[rootObject crashSegv];
// Confirm the app is not running.
XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning);
// TODO: Query the app for crash data
[_app launch];
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
[rootObject_ crashSegv];
#if defined(NDEBUG)
#if TARGET_OS_SIMULATOR
[self verifyCrashReportException:SIGINT];
#else
[self verifyCrashReportException:SIGABRT];
#endif
#else
[self verifyCrashReportException:SIGHUP];
#endif
}
- (void)testKillAbort {
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
// Crash the app.
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
[rootObject crashKillAbort];
// Confirm the app is not running.
XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning);
// TODO: Query the app for crash data
[_app launch];
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
[rootObject_ crashKillAbort];
[self verifyCrashReportException:SIGABRT];
}
- (void)testTrap {
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
// Crash the app.
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
[rootObject crashTrap];
// Confirm the app is not running.
XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning);
// TODO: Query the app for crash data
[_app launch];
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
[rootObject_ crashTrap];
#if TARGET_OS_SIMULATOR
[self verifyCrashReportException:SIGINT];
#else
[self verifyCrashReportException:SIGABRT];
#endif
}
- (void)testAbort {
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
// Crash the app.
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
[rootObject crashAbort];
// Confirm the app is not running.
XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning);
// TODO: Query the app for crash data
[_app launch];
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
[rootObject_ crashAbort];
[self verifyCrashReportException:SIGABRT];
}
- (void)testBadAccess {
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
// Crash the app.
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
[rootObject crashBadAccess];
// Confirm the app is not running.
XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning);
// TODO: Query the app for crash data
[_app launch];
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
[rootObject_ crashBadAccess];
#if defined(NDEBUG)
#if TARGET_OS_SIMULATOR
[self verifyCrashReportException:SIGINT];
#else
[self verifyCrashReportException:SIGABRT];
#endif
#else
[self verifyCrashReportException:SIGHUP];
#endif
}
- (void)testException {
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
// Crash the app.
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
[rootObject crashException];
// Confirm the app is not running.
XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning);
// TODO: Query the app for crash data
[_app launch];
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
[rootObject_ crashException];
[self verifyCrashReportException:SIGABRT];
}
- (void)testNSException {
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
// Crash the app.
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
[rootObject crashNSException];
// Confirm the app is not running.
XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning);
// TODO: Query the app for crash data
[_app launch];
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
[rootObject_ crashNSException];
[self verifyCrashReportException:crashpad::kMachExceptionFromNSException];
NSDictionary* dict = [rootObject_ getAnnotations];
NSString* userInfo =
[dict[@"objects"][0] valueForKeyPath:@"exceptionUserInfo"];
XCTAssertTrue([userInfo containsString:@"Error Object=<CPTestSharedObject"]);
XCTAssertTrue([[dict[@"objects"][1] valueForKeyPath:@"exceptionReason"]
isEqualToString:@"Intentionally throwing error."]);
XCTAssertTrue([[dict[@"objects"][2] valueForKeyPath:@"exceptionName"]
isEqualToString:@"NSInternalInconsistencyException"]);
}
- (void)testCrashUnreocgnizedSelectorAfterDelay {
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
// Crash the app.
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
[rootObject crashUnreocgnizedSelectorAfterDelay];
// Confirm the app is not running.
XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning);
// TODO: Query the app for crash data
[_app launch];
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
- (void)testcrashUnrecognizedSelectorAfterDelay {
[rootObject_ crashUnrecognizedSelectorAfterDelay];
[self verifyCrashReportException:crashpad::kMachExceptionFromNSException];
NSDictionary* dict = [rootObject_ getAnnotations];
XCTAssertTrue([[dict[@"objects"][0] valueForKeyPath:@"exceptionReason"]
containsString:
@"CPTestSharedObject does_not_exist]: unrecognized selector"]);
XCTAssertTrue([[dict[@"objects"][1] valueForKeyPath:@"exceptionName"]
isEqualToString:@"NSInvalidArgumentException"]);
}
- (void)testCatchUIGestureEnvironmentNSException {
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
// Tap the button with the string UIGestureEnvironmentException.
[_app.buttons[@"UIGestureEnvironmentException"] tap];
// Confirm the app is not running.
XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning);
// TODO: Query the app for crash data
[_app launch];
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
[app_.buttons[@"UIGestureEnvironmentException"] tap];
[self verifyCrashReportException:crashpad::kMachExceptionFromNSException];
NSDictionary* dict = [rootObject_ getAnnotations];
XCTAssertTrue([[dict[@"objects"][0] valueForKeyPath:@"exceptionReason"]
containsString:@"NSArray0 objectAtIndex:]: index 42 beyond bounds"]);
XCTAssertTrue([[dict[@"objects"][1] valueForKeyPath:@"exceptionName"]
isEqualToString:@"NSRangeException"]);
}
- (void)testCatchNSException {
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
[rootObject_ catchNSException];
// The app should not crash
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
[rootObject catchNSException];
XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground);
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
// No report should be generated.
[rootObject_ processIntermediateDumps];
XCTAssertEqual([rootObject_ pendingReportCount], 0);
}
- (void)testRecursion {
// TODO(justincohen): Crashpad iOS does not currently support stack type
// crashes.
return;
[rootObject_ crashRecursion];
[self verifyCrashReportException:SIGHUP];
}
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
- (void)testCrashWithCrashInfoMessage {
if (@available(iOS 15.0, *)) {
// Figure out how to test this on iOS15.
return;
}
[rootObject_ crashWithCrashInfoMessage];
[self verifyCrashReportException:SIGHUP];
NSDictionary* dict = [rootObject_ getAnnotations];
NSString* dyldMessage = dict[@"vector"][0];
XCTAssertTrue([dyldMessage isEqualToString:@"dyld: in dlsym()"]);
}
// Crash the app.
CPTestSharedObject* rootObject = [EDOClientService rootObjectWithPort:12345];
[rootObject crashRecursion];
// TODO(justincohen): Codesign crashy_initializer.so so it can run on devices.
#if !TARGET_OS_SIMULATOR
- (void)testCrashWithDyldErrorString {
if (@available(iOS 15.0, *)) {
// iOS 15 uses dyld4, which doesn't use CRSetCrashLogMessage2
return;
}
[rootObject_ crashWithDyldErrorString];
[self verifyCrashReportException:SIGINT];
NSArray* vector = [rootObject_ getAnnotations][@"vector"];
// This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp
// ImageLoaderMachO::doInitialization().
NSString* module = @"crashpad_snapshot_test_module_crashy_initializer.so";
XCTAssertTrue([vector[0] hasSuffix:module]);
}
#endif
// Confirm the app is not running.
XCTAssertTrue([_app waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(_app.state == XCUIApplicationStateNotRunning);
- (void)testCrashWithAnnotations {
[rootObject_ crashWithAnnotations];
[self verifyCrashReportException:SIGABRT];
NSDictionary* dict = [rootObject_ getAnnotations];
NSDictionary* simpleMap = dict[@"simplemap"];
XCTAssertTrue([simpleMap[@"#TEST# empty_value"] isEqualToString:@""]);
XCTAssertTrue([simpleMap[@"#TEST# key"] isEqualToString:@"value"]);
XCTAssertTrue([simpleMap[@"#TEST# longer"] isEqualToString:@"shorter"]);
XCTAssertTrue([simpleMap[@"#TEST# pad"] isEqualToString:@"crash"]);
XCTAssertTrue([simpleMap[@"#TEST# x"] isEqualToString:@"y"]);
// TODO: Query the app for crash data
[_app launch];
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
XCTAssertTrue([[dict[@"objects"][0] valueForKeyPath:@"#TEST# same-name"]
isEqualToString:@"same-name 4"]);
XCTAssertTrue([[dict[@"objects"][1] valueForKeyPath:@"#TEST# same-name"]
isEqualToString:@"same-name 3"]);
XCTAssertTrue([[dict[@"objects"][2] valueForKeyPath:@"#TEST# one"]
isEqualToString:@"moocow"]);
}
@end

View File

@ -42,6 +42,7 @@ static_library("app_host_sources") {
":app_shared_sources",
"../../../build:ios_enable_arc",
"../../../client",
"../../../snapshot",
"../../../third_party/edo",
]
frameworks = [
@ -50,8 +51,21 @@ static_library("app_host_sources") {
]
}
# TODO(justincohen): Codesign crashy_initializer.so so it can run on devices.
bundle_data("crashy_module_bundle") {
testonly = true
sources =
[ "$root_out_dir/crashpad_snapshot_test_module_crashy_initializer.so" ]
outputs = [ "{{bundle_contents_dir}}/crashpad_snapshot_test_module_crashy_initializer.so" ]
public_deps =
[ "../../../snapshot:crashpad_snapshot_test_module_crashy_initializer" ]
}
ios_app_bundle("ios_crash_xcuitests") {
info_plist = "Info.plist"
testonly = true
deps = [ ":app_host_sources" ]
deps = [
":app_host_sources",
":crashy_module_bundle",
]
}

View File

@ -13,8 +13,11 @@
// limitations under the License.
#import "test/ios/host/cptest_application_delegate.h"
#include <dispatch/dispatch.h>
#include <dlfcn.h>
#include <mach-o/dyld.h>
#include <mach-o/dyld_images.h>
#include <mach-o/nlist.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
@ -24,7 +27,15 @@
#import "Service/Sources/EDOHostNamingService.h"
#import "Service/Sources/EDOHostService.h"
#import "Service/Sources/NSObject+EDOValueObject.h"
#include "base/strings/sys_string_conversions.h"
#include "client/annotation.h"
#include "client/annotation_list.h"
#include "client/crash_report_database.h"
#include "client/crashpad_client.h"
#include "client/crashpad_info.h"
#include "client/simple_string_dictionary.h"
#include "snapshot/minidump/process_snapshot_minidump.h"
#import "test/ios/host/cptest_crash_view_controller.h"
#import "test/ios/host/cptest_shared_object.h"
@ -32,15 +43,58 @@
#error "This file requires ARC support."
#endif
@implementation CPTestApplicationDelegate
using OperationStatus = crashpad::CrashReportDatabase::OperationStatus;
using Report = crashpad::CrashReportDatabase::Report;
namespace {
base::FilePath GetDatabaseDir() {
base::FilePath database_dir([NSFileManager.defaultManager
URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask]
.lastObject.path.UTF8String);
return database_dir.Append("crashpad");
}
std::unique_ptr<crashpad::CrashReportDatabase> GetDatabase() {
base::FilePath database_dir = GetDatabaseDir();
std::unique_ptr<crashpad::CrashReportDatabase> database =
crashpad::CrashReportDatabase::Initialize(database_dir);
return database;
}
OperationStatus GetPendingReports(std::vector<Report>* pending_reports) {
std::unique_ptr<crashpad::CrashReportDatabase> database(GetDatabase());
return database->GetPendingReports(pending_reports);
}
[[clang::optnone]] void recurse(int counter) {
// Fill up the stack faster.
int arr[1024];
arr[0] = counter;
if (counter > INT_MAX)
return;
recurse(++counter);
}
} // namespace
@interface CPTestApplicationDelegate ()
- (void)processIntermediateDumps;
@end
@implementation CPTestApplicationDelegate {
crashpad::CrashpadClient client_;
}
@synthesize window = _window;
- (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
// Start up crashpad.
crashpad::CrashpadClient client;
client.StartCrashpadInProcessHandler(base::FilePath(), "", {});
if (client_.StartCrashpadInProcessHandler(GetDatabaseDir(), "", {})) {
client_.ProcessIntermediateDumps();
}
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];
@ -54,9 +108,14 @@
[EDOHostService serviceWithPort:12345
rootObject:[[CPTestSharedObject alloc] init]
queue:dispatch_get_main_queue()];
return YES;
}
- (void)processIntermediateDumps {
client_.ProcessIntermediateDumps();
}
@end
@implementation CPTestSharedObject
@ -65,6 +124,85 @@
return @"crashpad";
}
- (void)processIntermediateDumps {
CPTestApplicationDelegate* delegate =
(CPTestApplicationDelegate*)UIApplication.sharedApplication.delegate;
[delegate processIntermediateDumps];
}
- (void)clearPendingReports {
std::unique_ptr<crashpad::CrashReportDatabase> database(GetDatabase());
std::vector<crashpad::CrashReportDatabase::Report> pending_reports;
database->GetPendingReports(&pending_reports);
for (auto report : pending_reports) {
database->DeleteReport(report.uuid);
}
}
- (int)pendingReportCount {
std::vector<Report> pending_reports;
OperationStatus status = GetPendingReports(&pending_reports);
if (status != crashpad::CrashReportDatabase::kNoError) {
return -1;
}
return pending_reports.size();
}
- (int)pendingReportException {
std::vector<Report> pending_reports;
OperationStatus status = GetPendingReports(&pending_reports);
if (status != crashpad::CrashReportDatabase::kNoError ||
pending_reports.size() != 1) {
return -1;
}
auto reader = std::make_unique<crashpad::FileReader>();
reader->Open(pending_reports[0].file_path);
crashpad::ProcessSnapshotMinidump process_snapshot;
process_snapshot.Initialize(reader.get());
return static_cast<int>(process_snapshot.Exception()->Exception());
}
- (NSDictionary*)getAnnotations {
std::vector<Report> pending_reports;
OperationStatus status = GetPendingReports(&pending_reports);
if (status != crashpad::CrashReportDatabase::kNoError ||
pending_reports.size() != 1) {
return @{};
}
auto reader = std::make_unique<crashpad::FileReader>();
reader->Open(pending_reports[0].file_path);
crashpad::ProcessSnapshotMinidump process_snapshot;
process_snapshot.Initialize(reader.get());
NSDictionary* dict = @{
@"simplemap" : [@{} mutableCopy],
@"vector" : [@[] mutableCopy],
@"objects" : [@[] mutableCopy]
};
for (const auto* module : process_snapshot.Modules()) {
for (const auto& kv : module->AnnotationsSimpleMap()) {
[dict[@"simplemap"] setValue:@(kv.second.c_str())
forKey:@(kv.first.c_str())];
}
for (const std::string& annotation : module->AnnotationsVector()) {
[dict[@"vector"] addObject:@(annotation.c_str())];
}
for (const auto& annotation : module->AnnotationObjects()) {
if (annotation.type !=
static_cast<uint16_t>(crashpad::Annotation::Type::kString)) {
continue;
}
std::string value(reinterpret_cast<const char*>(annotation.value.data()),
annotation.value.size());
[dict[@"objects"]
addObject:@{@(annotation.name.c_str()) : @(value.c_str())}];
}
}
return [dict passByValue];
}
- (void)crashBadAccess {
strcpy(nullptr, "bla");
}
@ -92,13 +230,25 @@
}
- (void)crashNSException {
// EDO has its own sinkhole.
// EDO has its own sinkhole, so dispatch this away.
dispatch_async(dispatch_get_main_queue(), ^{
NSArray* empty_array = @[];
[empty_array objectAtIndex:42];
NSError* error = [NSError errorWithDomain:@"com.crashpad.xcuitests"
code:200
userInfo:@{@"Error Object" : self}];
[[NSException exceptionWithName:NSInternalInconsistencyException
reason:@"Intentionally throwing error."
userInfo:@{NSUnderlyingErrorKey : error}] raise];
});
}
- (void)crashUnrecognizedSelectorAfterDelay {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
[self performSelector:@selector(does_not_exist) withObject:nil afterDelay:1];
#pragma clang diagnostic pop
}
- (void)catchNSException {
@try {
NSArray* empty_array = @[];
@ -108,19 +258,53 @@
}
}
- (void)crashUnreocgnizedSelectorAfterDelay {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
[self performSelector:@selector(does_not_exist) withObject:nil afterDelay:1];
#pragma clang diagnostic pop
}
- (void)recurse {
[self recurse];
}
- (void)crashRecursion {
[self recurse];
recurse(0);
}
- (void)crashWithCrashInfoMessage {
dlsym(nullptr, nullptr);
}
- (void)crashWithDyldErrorString {
std::string crashy_initializer =
base::SysNSStringToUTF8([[NSBundle mainBundle]
pathForResource:@"crashpad_snapshot_test_module_crashy_initializer"
ofType:@"so"]);
dlopen(crashy_initializer.c_str(), RTLD_LAZY | RTLD_LOCAL);
}
- (void)crashWithAnnotations {
// This is “leaked” to crashpad_info.
crashpad::SimpleStringDictionary* simple_annotations =
new crashpad::SimpleStringDictionary();
simple_annotations->SetKeyValue("#TEST# pad", "break");
simple_annotations->SetKeyValue("#TEST# key", "value");
simple_annotations->SetKeyValue("#TEST# pad", "crash");
simple_annotations->SetKeyValue("#TEST# x", "y");
simple_annotations->SetKeyValue("#TEST# longer", "shorter");
simple_annotations->SetKeyValue("#TEST# empty_value", "");
crashpad::CrashpadInfo* crashpad_info =
crashpad::CrashpadInfo::GetCrashpadInfo();
crashpad_info->set_simple_annotations(simple_annotations);
crashpad::AnnotationList::Register(); // This is “leaked” to crashpad_info.
static crashpad::StringAnnotation<32> test_annotation_one{"#TEST# one"};
static crashpad::StringAnnotation<32> test_annotation_two{"#TEST# two"};
static crashpad::StringAnnotation<32> test_annotation_three{
"#TEST# same-name"};
static crashpad::StringAnnotation<32> test_annotation_four{
"#TEST# same-name"};
test_annotation_one.Set("moocow");
test_annotation_two.Set("this will be cleared");
test_annotation_three.Set("same-name 3");
test_annotation_four.Set("same-name 4");
test_annotation_two.Clear();
abort();
}
@end

View File

@ -58,7 +58,6 @@
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = UIColor.redColor;
}

View File

@ -18,9 +18,30 @@
#import <UIKit/UIKit.h>
@interface CPTestSharedObject : NSObject
// Returns the string "crashpad" for testing EDO.
- (NSString*)testEDO;
// Tell Crashpad to process intermediate dumps.
- (void)processIntermediateDumps;
// Clear pending reports from Crashpad database.
- (void)clearPendingReports;
// Returns the number of pending reports, or -1 if there's an error getting
// report.
- (int)pendingReportCount;
// Returns exception code when there's a single pending report, or -1 if there's
// a different number of pending reports.
- (int)pendingReportException;
// Return an NSDictionary with a dictionary named "simplemap", an array named
// "vector" and an array named "objects", representing the combination of all
// modules AnnotationsSimpleMap, AnnotationsVector and AnnotationObjects
// (strings only) respectively.
- (NSDictionary*)getAnnotations;
// Triggers an EXC_BAD_ACCESS exception and crash.
- (void)crashBadAccess;
@ -43,13 +64,22 @@
- (void)crashNSException;
// Trigger an unrecognized selector after delay.
- (void)crashUnreocgnizedSelectorAfterDelay;
- (void)crashUnrecognizedSelectorAfterDelay;
// Trigger a caught NSxception.
// Trigger a caught NSException, this will not crash
- (void)catchNSException;
// Trigger a crash with an infinite recursion.
- (void)crashRecursion;
// Trigger a crash dlsym that contains a crash_info message.
- (void)crashWithCrashInfoMessage;
// Trigger an error that will to the dyld error string `_error_string`
- (void)crashWithDyldErrorString;
// Trigger a crash after writing various annotations.
- (void)crashWithAnnotations;
@end
#endif // CRASHPAD_TEST_IOS_HOST_SHARED_OBJECT_H_