mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-27 07:14:10 +08:00
Add another iOS library path sinkhole.
Add another sinkhole for _UIGestureEnvironmentUpdate. Bug: crashpad:31 Change-Id: Ic4a424da034249295b6e45f8fe0860a4d4696b93 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2145017 Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org> Reviewed-by: Justin Cohen <justincohen@chromium.org> Reviewed-by: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
parent
7fa69e7e43
commit
ea4af71c2a
8
BUILD.gn
8
BUILD.gn
@ -45,7 +45,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
|
||||
"handler:handler_test",
|
||||
"minidump:minidump_test",
|
||||
"snapshot:snapshot_test",
|
||||
"util:util_test",
|
||||
]
|
||||
}
|
||||
if (crashpad_is_in_fuchsia) {
|
||||
@ -63,9 +62,7 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
|
||||
"util/net/testdata/binary_http_body.dat",
|
||||
]
|
||||
|
||||
outputs = [
|
||||
"$root_out_dir/crashpad_test_data/{{source}}",
|
||||
]
|
||||
outputs = [ "$root_out_dir/crashpad_test_data/{{source}}" ]
|
||||
}
|
||||
|
||||
deps += [ ":crashpad_test_data" ]
|
||||
@ -222,9 +219,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
|
||||
"test:gmock_main",
|
||||
"util:util_test",
|
||||
]
|
||||
if (crashpad_is_ios) {
|
||||
deps -= [ "util:util_test" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,6 +193,21 @@
|
||||
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
|
||||
}
|
||||
|
||||
- (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);
|
||||
}
|
||||
|
||||
- (void)testCatchNSException {
|
||||
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
|
||||
|
||||
|
@ -22,6 +22,40 @@
|
||||
|
||||
- (void)loadView {
|
||||
self.view = [[UIView alloc] init];
|
||||
|
||||
UIStackView* buttonStack = [[UIStackView alloc] init];
|
||||
buttonStack.axis = UILayoutConstraintAxisVertical;
|
||||
buttonStack.spacing = 6;
|
||||
|
||||
UIButton* button = [UIButton new];
|
||||
[button setTitle:@"UIGestureEnvironmentException"
|
||||
forState:UIControlStateNormal];
|
||||
UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc]
|
||||
initWithTarget:self
|
||||
action:@selector(throwUIGestureEnvironmentException)];
|
||||
[button addGestureRecognizer:tapGesture];
|
||||
[button setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
[button.widthAnchor constraintEqualToConstant:16.0].active = YES;
|
||||
[button.heightAnchor constraintEqualToConstant:16.0].active = YES;
|
||||
|
||||
[buttonStack addArrangedSubview:button];
|
||||
|
||||
[self.view addSubview:buttonStack];
|
||||
|
||||
[buttonStack setTranslatesAutoresizingMaskIntoConstraints:NO];
|
||||
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[buttonStack.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
|
||||
[buttonStack.topAnchor constraintEqualToAnchor:self.view.topAnchor],
|
||||
[buttonStack.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
|
||||
[buttonStack.trailingAnchor
|
||||
constraintEqualToAnchor:self.view.trailingAnchor],
|
||||
]];
|
||||
}
|
||||
|
||||
- (void)throwUIGestureEnvironmentException {
|
||||
NSArray* empty_array = @[];
|
||||
[empty_array objectAtIndex:42];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
|
@ -548,7 +548,7 @@ static_library("util") {
|
||||
configs += [ "..:disable_ubsan" ]
|
||||
}
|
||||
|
||||
if (!crashpad_is_android) {
|
||||
if (!crashpad_is_android && !crashpad_is_ios) {
|
||||
crashpad_executable("http_transport_test_server") {
|
||||
testonly = true
|
||||
sources = [ "net/http_transport_test_server.cc" ]
|
||||
@ -639,13 +639,13 @@ source_set("util_test") {
|
||||
"thread/worker_thread_test.cc",
|
||||
]
|
||||
|
||||
if (!crashpad_is_android) {
|
||||
if (!crashpad_is_android && !crashpad_is_ios) {
|
||||
# Android requires an HTTPTransport implementation.
|
||||
sources += [ "net/http_transport_test.cc" ]
|
||||
}
|
||||
|
||||
if (crashpad_is_posix || crashpad_is_fuchsia) {
|
||||
if (!crashpad_is_fuchsia) {
|
||||
if (!crashpad_is_fuchsia && !crashpad_is_ios) {
|
||||
sources += [
|
||||
"posix/process_info_test.cc",
|
||||
"posix/signals_test.cc",
|
||||
@ -680,6 +680,27 @@ source_set("util_test") {
|
||||
]
|
||||
}
|
||||
|
||||
if (crashpad_is_ios) {
|
||||
sources += [ "ios/exception_processor_test.mm" ]
|
||||
|
||||
sources -= [
|
||||
"file/directory_reader_test.cc",
|
||||
"file/file_io_test.cc",
|
||||
"file/filesystem_test.cc",
|
||||
"misc/capture_context_test.cc",
|
||||
"misc/clock_test.cc",
|
||||
"misc/paths_test.cc",
|
||||
"net/http_body_test.cc",
|
||||
"net/http_multipart_builder_test.cc",
|
||||
"process/process_memory_range_test.cc",
|
||||
"process/process_memory_test.cc",
|
||||
"stream/file_encoder_test.cc",
|
||||
"synchronization/semaphore_test.cc",
|
||||
"thread/thread_test.cc",
|
||||
"thread/worker_thread_test.cc",
|
||||
]
|
||||
}
|
||||
|
||||
if (crashpad_is_linux || crashpad_is_android) {
|
||||
sources += [
|
||||
"linux/auxiliary_vector_test.cc",
|
||||
@ -739,7 +760,7 @@ source_set("util_test") {
|
||||
deps += [ "../third_party/lss" ]
|
||||
}
|
||||
|
||||
if (!crashpad_is_android) {
|
||||
if (!crashpad_is_android && !crashpad_is_ios) {
|
||||
data_deps = [ ":http_transport_test_server" ]
|
||||
|
||||
if (crashpad_use_boringssl_for_http_transport_socket) {
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <dlfcn.h>
|
||||
#include <libunwind.h>
|
||||
#include <mach-o/loader.h>
|
||||
#include <objc/message.h>
|
||||
#include <objc/objc-exception.h>
|
||||
#include <objc/objc.h>
|
||||
#include <objc/runtime.h>
|
||||
@ -109,6 +110,14 @@ bool ModulePathMatchesSinkhole(const char* path, const char* sinkhole) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int LoggingUnwStep(unw_cursor_t* cursor) {
|
||||
int rv = unw_step(cursor);
|
||||
if (rv < 0) {
|
||||
LOG(ERROR) << "unw_step: " << rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
id ObjcExceptionPreprocessor(id exception) {
|
||||
// Unwind the stack looking for any exception handlers. If an exception
|
||||
// handler is encountered, test to see if it is a function known to catch-
|
||||
@ -152,7 +161,7 @@ id ObjcExceptionPreprocessor(id exception) {
|
||||
exception_header->unwindHeader.exception_class = kOurExceptionClass;
|
||||
|
||||
bool handler_found = false;
|
||||
while (unw_step(&cursor) > 0) {
|
||||
while (LoggingUnwStep(&cursor) > 0) {
|
||||
unw_proc_info_t frame_info;
|
||||
if (unw_get_proc_info(&cursor, &frame_info) != UNW_ESUCCESS) {
|
||||
continue;
|
||||
@ -226,14 +235,14 @@ id ObjcExceptionPreprocessor(id exception) {
|
||||
// Everything in this library is a sinkhole, specifically
|
||||
// _dispatch_client_callout. Both are needed here depending on whether
|
||||
// the debugger is attached (introspection only appears when a simulator
|
||||
// is attached to a debugger.
|
||||
// only).
|
||||
// is attached to a debugger).
|
||||
"/usr/lib/system/introspection/libdispatch.dylib",
|
||||
"/usr/lib/system/libdispatch.dylib",
|
||||
|
||||
// __CFRunLoopDoTimers and __CFRunLoopRun are sinkholes. Consider also
|
||||
// checking that a few frames up is CFRunLoopRunSpecific().
|
||||
"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"};
|
||||
"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation",
|
||||
};
|
||||
|
||||
Dl_info dl_info;
|
||||
if (dladdr(reinterpret_cast<const void*>(frame_info.start_ip), &dl_info) !=
|
||||
@ -245,6 +254,44 @@ id ObjcExceptionPreprocessor(id exception) {
|
||||
}
|
||||
}
|
||||
|
||||
// Some <redacted> sinkholes are harder to find. _UIGestureEnvironmentUpdate
|
||||
// in UIKitCore is an example. UIKitCore can't be added to
|
||||
// kExceptionLibraryPathSinkholes because it uses Objective-C exceptions
|
||||
// internally and also has has non-sinkhole handlers. Since
|
||||
// _UIGestureEnvironmentUpdate is always called from
|
||||
// -[UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:],
|
||||
// inspect the caller frame info to match the sinkhole.
|
||||
constexpr const char* kUIKitCorePath =
|
||||
"/System/Library/PrivateFrameworks/UIKitCore.framework/UIKitCore";
|
||||
if (ModulePathMatchesSinkhole(dl_info.dli_fname, kUIKitCorePath)) {
|
||||
unw_proc_info_t caller_frame_info;
|
||||
if (LoggingUnwStep(&cursor) > 0 &&
|
||||
unw_get_proc_info(&cursor, &caller_frame_info) == UNW_ESUCCESS) {
|
||||
static IMP uigesture_deliver_event_imp = [] {
|
||||
IMP imp = class_getMethodImplementation(
|
||||
NSClassFromString(@"UIGestureEnvironment"),
|
||||
NSSelectorFromString(
|
||||
@"_deliverEvent:toGestureRecognizers:usingBlock:"));
|
||||
|
||||
// From 10.15.0 objc4-779.1/runtime/objc-class.mm
|
||||
// class_getMethodImplementation returns nil or _objc_msgForward on
|
||||
// failure.
|
||||
if (!imp || imp == _objc_msgForward) {
|
||||
LOG(WARNING) << "Unable to find -[UIGestureEnvironment "
|
||||
"_deliverEvent:toGestureRecognizers:usingBlock:]";
|
||||
return reinterpret_cast<IMP>(NULL);
|
||||
}
|
||||
return imp;
|
||||
}();
|
||||
|
||||
if (uigesture_deliver_event_imp ==
|
||||
reinterpret_cast<IMP>(caller_frame_info.start_ip)) {
|
||||
TerminatingFromUncaughtNSException(exception,
|
||||
"_UIGestureEnvironmentUpdate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handler_found = true;
|
||||
|
||||
break;
|
||||
|
41
util/ios/exception_processor_test.mm
Normal file
41
util/ios/exception_processor_test.mm
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2020 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <objc/message.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "testing/platform_test.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
using IOSExceptionProcessor = PlatformTest;
|
||||
|
||||
TEST_F(IOSExceptionProcessor, SelectorExists) {
|
||||
IMP uigesture_deliver_event_imp = class_getMethodImplementation(
|
||||
NSClassFromString(@"UIGestureEnvironment"),
|
||||
NSSelectorFromString(@"_deliverEvent:toGestureRecognizers:usingBlock:"));
|
||||
|
||||
// From 10.15.0 objc4-779.1/runtime/objc-class.mm
|
||||
// class_getMethodImplementation returns nil or _objc_msgForward on failure.
|
||||
ASSERT_TRUE(uigesture_deliver_event_imp);
|
||||
ASSERT_NE(uigesture_deliver_event_imp, _objc_msgForward);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
Loading…
x
Reference in New Issue
Block a user