mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-17 08:33:54 +00: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",
|
"handler:handler_test",
|
||||||
"minidump:minidump_test",
|
"minidump:minidump_test",
|
||||||
"snapshot:snapshot_test",
|
"snapshot:snapshot_test",
|
||||||
"util:util_test",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if (crashpad_is_in_fuchsia) {
|
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",
|
"util/net/testdata/binary_http_body.dat",
|
||||||
]
|
]
|
||||||
|
|
||||||
outputs = [
|
outputs = [ "$root_out_dir/crashpad_test_data/{{source}}" ]
|
||||||
"$root_out_dir/crashpad_test_data/{{source}}",
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deps += [ ":crashpad_test_data" ]
|
deps += [ ":crashpad_test_data" ]
|
||||||
@ -222,9 +219,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
|
|||||||
"test:gmock_main",
|
"test:gmock_main",
|
||||||
"util:util_test",
|
"util:util_test",
|
||||||
]
|
]
|
||||||
if (crashpad_is_ios) {
|
|
||||||
deps -= [ "util:util_test" ]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,6 +193,21 @@
|
|||||||
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
|
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 {
|
- (void)testCatchNSException {
|
||||||
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
|
XCTAssertTrue(_app.state == XCUIApplicationStateRunningForeground);
|
||||||
|
|
||||||
|
@ -22,6 +22,40 @@
|
|||||||
|
|
||||||
- (void)loadView {
|
- (void)loadView {
|
||||||
self.view = [[UIView alloc] init];
|
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 {
|
- (void)viewDidLoad {
|
||||||
|
@ -548,7 +548,7 @@ static_library("util") {
|
|||||||
configs += [ "..:disable_ubsan" ]
|
configs += [ "..:disable_ubsan" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!crashpad_is_android) {
|
if (!crashpad_is_android && !crashpad_is_ios) {
|
||||||
crashpad_executable("http_transport_test_server") {
|
crashpad_executable("http_transport_test_server") {
|
||||||
testonly = true
|
testonly = true
|
||||||
sources = [ "net/http_transport_test_server.cc" ]
|
sources = [ "net/http_transport_test_server.cc" ]
|
||||||
@ -639,13 +639,13 @@ source_set("util_test") {
|
|||||||
"thread/worker_thread_test.cc",
|
"thread/worker_thread_test.cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
if (!crashpad_is_android) {
|
if (!crashpad_is_android && !crashpad_is_ios) {
|
||||||
# Android requires an HTTPTransport implementation.
|
# Android requires an HTTPTransport implementation.
|
||||||
sources += [ "net/http_transport_test.cc" ]
|
sources += [ "net/http_transport_test.cc" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crashpad_is_posix || crashpad_is_fuchsia) {
|
if (crashpad_is_posix || crashpad_is_fuchsia) {
|
||||||
if (!crashpad_is_fuchsia) {
|
if (!crashpad_is_fuchsia && !crashpad_is_ios) {
|
||||||
sources += [
|
sources += [
|
||||||
"posix/process_info_test.cc",
|
"posix/process_info_test.cc",
|
||||||
"posix/signals_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) {
|
if (crashpad_is_linux || crashpad_is_android) {
|
||||||
sources += [
|
sources += [
|
||||||
"linux/auxiliary_vector_test.cc",
|
"linux/auxiliary_vector_test.cc",
|
||||||
@ -739,7 +760,7 @@ source_set("util_test") {
|
|||||||
deps += [ "../third_party/lss" ]
|
deps += [ "../third_party/lss" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!crashpad_is_android) {
|
if (!crashpad_is_android && !crashpad_is_ios) {
|
||||||
data_deps = [ ":http_transport_test_server" ]
|
data_deps = [ ":http_transport_test_server" ]
|
||||||
|
|
||||||
if (crashpad_use_boringssl_for_http_transport_socket) {
|
if (crashpad_use_boringssl_for_http_transport_socket) {
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <libunwind.h>
|
#include <libunwind.h>
|
||||||
#include <mach-o/loader.h>
|
#include <mach-o/loader.h>
|
||||||
|
#include <objc/message.h>
|
||||||
#include <objc/objc-exception.h>
|
#include <objc/objc-exception.h>
|
||||||
#include <objc/objc.h>
|
#include <objc/objc.h>
|
||||||
#include <objc/runtime.h>
|
#include <objc/runtime.h>
|
||||||
@ -109,6 +110,14 @@ bool ModulePathMatchesSinkhole(const char* path, const char* sinkhole) {
|
|||||||
#endif
|
#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) {
|
id ObjcExceptionPreprocessor(id exception) {
|
||||||
// Unwind the stack looking for any exception handlers. If an 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-
|
// 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;
|
exception_header->unwindHeader.exception_class = kOurExceptionClass;
|
||||||
|
|
||||||
bool handler_found = false;
|
bool handler_found = false;
|
||||||
while (unw_step(&cursor) > 0) {
|
while (LoggingUnwStep(&cursor) > 0) {
|
||||||
unw_proc_info_t frame_info;
|
unw_proc_info_t frame_info;
|
||||||
if (unw_get_proc_info(&cursor, &frame_info) != UNW_ESUCCESS) {
|
if (unw_get_proc_info(&cursor, &frame_info) != UNW_ESUCCESS) {
|
||||||
continue;
|
continue;
|
||||||
@ -226,14 +235,14 @@ id ObjcExceptionPreprocessor(id exception) {
|
|||||||
// Everything in this library is a sinkhole, specifically
|
// Everything in this library is a sinkhole, specifically
|
||||||
// _dispatch_client_callout. Both are needed here depending on whether
|
// _dispatch_client_callout. Both are needed here depending on whether
|
||||||
// the debugger is attached (introspection only appears when a simulator
|
// the debugger is attached (introspection only appears when a simulator
|
||||||
// is attached to a debugger.
|
// is attached to a debugger).
|
||||||
// only).
|
|
||||||
"/usr/lib/system/introspection/libdispatch.dylib",
|
"/usr/lib/system/introspection/libdispatch.dylib",
|
||||||
"/usr/lib/system/libdispatch.dylib",
|
"/usr/lib/system/libdispatch.dylib",
|
||||||
|
|
||||||
// __CFRunLoopDoTimers and __CFRunLoopRun are sinkholes. Consider also
|
// __CFRunLoopDoTimers and __CFRunLoopRun are sinkholes. Consider also
|
||||||
// checking that a few frames up is CFRunLoopRunSpecific().
|
// checking that a few frames up is CFRunLoopRunSpecific().
|
||||||
"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation"};
|
"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation",
|
||||||
|
};
|
||||||
|
|
||||||
Dl_info dl_info;
|
Dl_info dl_info;
|
||||||
if (dladdr(reinterpret_cast<const void*>(frame_info.start_ip), &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;
|
handler_found = true;
|
||||||
|
|
||||||
break;
|
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