2014-10-17 13:47:02 -04:00
|
|
|
|
// Copyright 2014 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.
|
|
|
|
|
|
|
|
|
|
#include "snapshot/mac/mach_o_image_annotations_reader.h"
|
|
|
|
|
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
#include <mach/mach.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2016-01-06 12:22:50 -05:00
|
|
|
|
#include <sys/types.h>
|
2014-10-17 13:47:02 -04:00
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2015-08-05 18:24:53 -04:00
|
|
|
|
#include "base/files/file_path.h"
|
2016-01-06 12:22:50 -05:00
|
|
|
|
#include "base/macros.h"
|
2014-10-17 13:47:02 -04:00
|
|
|
|
#include "client/crashpad_info.h"
|
|
|
|
|
#include "client/simple_string_dictionary.h"
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
#include "snapshot/mac/process_reader.h"
|
test: Move util/test to its own top-level directory, test.
After 9e79ea1da719, it no longer makes sense for crashpad_util_test_lib
to “hide” in util/util_test.gyp. All of util/test is moved to its own
top-level directory, test, which all other test code is allowed to
depend on. test, too, is allowed to depend on all other non-test code.
In a future change, when crashpad_util_test_lib gains a dependency on
crashpad_client, it won’t look so weird for something in util (even
though it’s in util/test) to depend on something in client, because the
thing that needs to depend on client will live in test, not util.
BUG=crashpad:33
R=scottmg@chromium.org
Review URL: https://codereview.chromium.org/1051533002
2015-03-31 17:44:14 -04:00
|
|
|
|
#include "test/errors.h"
|
|
|
|
|
#include "test/mac/mach_errors.h"
|
|
|
|
|
#include "test/mac/mach_multiprocess.h"
|
2015-08-05 18:24:53 -04:00
|
|
|
|
#include "test/paths.h"
|
2014-12-17 14:35:18 -08:00
|
|
|
|
#include "util/file/file_io.h"
|
2014-10-17 13:47:02 -04:00
|
|
|
|
#include "util/mac/mac_util.h"
|
|
|
|
|
#include "util/mach/exc_server_variants.h"
|
|
|
|
|
#include "util/mach/exception_ports.h"
|
2015-04-02 15:28:28 -04:00
|
|
|
|
#include "util/mach/mach_extensions.h"
|
2014-12-10 11:11:21 -05:00
|
|
|
|
#include "util/mach/mach_message.h"
|
2014-10-17 13:47:02 -04:00
|
|
|
|
#include "util/mach/mach_message_server.h"
|
|
|
|
|
|
|
|
|
|
namespace crashpad {
|
|
|
|
|
namespace test {
|
|
|
|
|
namespace {
|
|
|
|
|
|
2015-08-07 13:59:45 -04:00
|
|
|
|
// \return The path to crashpad_snapshot_test_module_crashy_initializer.so
|
|
|
|
|
std::string ModuleWithCrashyInitializer() {
|
|
|
|
|
return Paths::Executable().value() + "_module_crashy_initializer.so";
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-05 18:24:53 -04:00
|
|
|
|
//! \return The path to the crashpad_snapshot_test_no_op executable.
|
|
|
|
|
base::FilePath NoOpExecutable() {
|
|
|
|
|
return base::FilePath(Paths::Executable().value() + "_no_op");
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:18:24 -05:00
|
|
|
|
class TestMachOImageAnnotationsReader final
|
|
|
|
|
: public MachMultiprocess,
|
|
|
|
|
public UniversalMachExcServer::Interface {
|
2014-10-17 13:47:02 -04:00
|
|
|
|
public:
|
|
|
|
|
enum TestType {
|
|
|
|
|
// Don’t crash, just test the CrashpadInfo interface.
|
|
|
|
|
kDontCrash = 0,
|
|
|
|
|
|
|
|
|
|
// The child process should crash by calling abort(). The parent verifies
|
|
|
|
|
// that the system libraries set the expected annotations.
|
2015-08-07 13:59:45 -04:00
|
|
|
|
//
|
|
|
|
|
// This test verifies that the message field in crashreporter_annotations_t
|
|
|
|
|
// can be recovered. Either 10.10.2 Libc-1044.1.2/stdlib/FreeBSD/abort.c
|
|
|
|
|
// abort() or 10.10.2 Libc-1044.10.1/sys/_libc_fork_child.c
|
|
|
|
|
// _libc_fork_child() calls CRSetCrashLogMessage() to set the message field.
|
2014-10-17 13:47:02 -04:00
|
|
|
|
kCrashAbort,
|
|
|
|
|
|
2015-08-07 13:59:45 -04:00
|
|
|
|
// The child process should crash at module initialization time, when dyld
|
|
|
|
|
// will have set an annotation matching the path of the module being
|
|
|
|
|
// initialized.
|
|
|
|
|
//
|
|
|
|
|
// This test exists to verify that the message2 field in
|
|
|
|
|
// crashreporter_annotations_t can be recovered. 10.10.2
|
|
|
|
|
// dyld-353.2.1/src/ImageLoaderMachO.cpp
|
|
|
|
|
// ImageLoaderMachO::doInitialization() calls CRSetCrashLogMessage2() to set
|
|
|
|
|
// the message2 field.
|
|
|
|
|
kCrashModuleInitialization,
|
|
|
|
|
|
2014-10-17 13:47:02 -04:00
|
|
|
|
// The child process should crash by setting DYLD_INSERT_LIBRARIES to
|
|
|
|
|
// contain a nonexistent library. The parent verifies that dyld sets the
|
|
|
|
|
// expected annotations.
|
|
|
|
|
kCrashDyld,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
explicit TestMachOImageAnnotationsReader(TestType test_type)
|
|
|
|
|
: MachMultiprocess(),
|
2014-12-04 10:18:24 -05:00
|
|
|
|
UniversalMachExcServer::Interface(),
|
2014-10-17 13:47:02 -04:00
|
|
|
|
test_type_(test_type) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~TestMachOImageAnnotationsReader() {}
|
|
|
|
|
|
2014-12-04 10:18:24 -05:00
|
|
|
|
// UniversalMachExcServer::Interface:
|
2014-10-17 13:47:02 -04:00
|
|
|
|
kern_return_t CatchMachException(exception_behavior_t behavior,
|
|
|
|
|
exception_handler_t exception_port,
|
|
|
|
|
thread_t thread,
|
|
|
|
|
task_t task,
|
|
|
|
|
exception_type_t exception,
|
|
|
|
|
const mach_exception_data_type_t* code,
|
|
|
|
|
mach_msg_type_number_t code_count,
|
|
|
|
|
thread_state_flavor_t* flavor,
|
2015-04-02 15:28:28 -04:00
|
|
|
|
ConstThreadState old_state,
|
2014-10-17 13:47:02 -04:00
|
|
|
|
mach_msg_type_number_t old_state_count,
|
|
|
|
|
thread_state_t new_state,
|
|
|
|
|
mach_msg_type_number_t* new_state_count,
|
2014-12-01 16:06:56 -05:00
|
|
|
|
const mach_msg_trailer_t* trailer,
|
2014-10-17 13:47:02 -04:00
|
|
|
|
bool* destroy_complex_request) override {
|
|
|
|
|
*destroy_complex_request = true;
|
|
|
|
|
|
2017-03-07 17:12:22 -05:00
|
|
|
|
if (test_type_ != kCrashDyld) {
|
|
|
|
|
// In 10.12.1 and later, the task port will not match ChildTask() in the
|
|
|
|
|
// kCrashDyld case, because kCrashDyld uses execl(), which results in a
|
|
|
|
|
// new task port being assigned.
|
|
|
|
|
EXPECT_EQ(ChildTask(), task);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The process ID should always compare favorably.
|
2016-11-02 20:06:39 -04:00
|
|
|
|
pid_t task_pid;
|
|
|
|
|
kern_return_t kr = pid_for_task(task, &task_pid);
|
|
|
|
|
EXPECT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "pid_for_task");
|
|
|
|
|
EXPECT_EQ(ChildPID(), task_pid);
|
2014-10-17 13:47:02 -04:00
|
|
|
|
|
|
|
|
|
ProcessReader process_reader;
|
|
|
|
|
bool rv = process_reader.Initialize(task);
|
|
|
|
|
if (!rv) {
|
|
|
|
|
ADD_FAILURE();
|
|
|
|
|
} else {
|
|
|
|
|
const std::vector<ProcessReader::Module>& modules =
|
|
|
|
|
process_reader.Modules();
|
|
|
|
|
std::vector<std::string> all_annotations_vector;
|
|
|
|
|
for (const ProcessReader::Module& module : modules) {
|
2015-03-08 21:02:42 -04:00
|
|
|
|
if (module.reader) {
|
|
|
|
|
MachOImageAnnotationsReader module_annotations_reader(
|
|
|
|
|
&process_reader, module.reader, module.name);
|
|
|
|
|
std::vector<std::string> module_annotations_vector =
|
|
|
|
|
module_annotations_reader.Vector();
|
|
|
|
|
all_annotations_vector.insert(all_annotations_vector.end(),
|
|
|
|
|
module_annotations_vector.begin(),
|
|
|
|
|
module_annotations_vector.end());
|
|
|
|
|
} else {
|
|
|
|
|
EXPECT_TRUE(module.reader);
|
|
|
|
|
}
|
2014-10-17 13:47:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mac OS X 10.6 doesn’t have support for CrashReporter annotations
|
|
|
|
|
// (CrashReporterClient.h), so don’t look for any special annotations in
|
|
|
|
|
// that version.
|
|
|
|
|
int mac_os_x_minor_version = MacOSXMinorVersion();
|
|
|
|
|
if (mac_os_x_minor_version > 7) {
|
|
|
|
|
EXPECT_GE(all_annotations_vector.size(), 1u);
|
|
|
|
|
|
2015-08-07 13:59:45 -04:00
|
|
|
|
std::string expected_annotation;
|
2014-10-17 13:47:02 -04:00
|
|
|
|
switch (test_type_) {
|
|
|
|
|
case kCrashAbort:
|
|
|
|
|
// The child process calls abort(), so the expected annotation
|
|
|
|
|
// reflects this, with a string set by 10.7.5
|
|
|
|
|
// Libc-763.13/stdlib/abort-fbsd.c abort(). This string is still
|
|
|
|
|
// present in 10.9.5 Libc-997.90.3/stdlib/FreeBSD/abort.c abort(),
|
|
|
|
|
// but because abort() tests to see if a message is already set and
|
|
|
|
|
// something else in Libc will have set a message, this string is
|
|
|
|
|
// not the expectation on 10.9 or higher. Instead, after fork(), the
|
|
|
|
|
// child process has a message indicating that a fork() without
|
|
|
|
|
// exec() occurred. See 10.9.5 Libc-997.90.3/sys/_libc_fork_child.c
|
|
|
|
|
// _libc_fork_child().
|
|
|
|
|
expected_annotation =
|
|
|
|
|
mac_os_x_minor_version <= 8
|
|
|
|
|
? "abort() called"
|
|
|
|
|
: "crashed on child side of fork pre-exec";
|
|
|
|
|
break;
|
|
|
|
|
|
2015-08-07 13:59:45 -04:00
|
|
|
|
case kCrashModuleInitialization:
|
|
|
|
|
// This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp
|
|
|
|
|
// ImageLoaderMachO::doInitialization().
|
|
|
|
|
expected_annotation = ModuleWithCrashyInitializer();
|
|
|
|
|
break;
|
|
|
|
|
|
2014-10-17 13:47:02 -04:00
|
|
|
|
case kCrashDyld:
|
|
|
|
|
// This is independent of dyld’s error_string, which is tested
|
|
|
|
|
// below.
|
|
|
|
|
expected_annotation = "dyld: launch, loading dependent libraries";
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ADD_FAILURE();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (const std::string& annotation : all_annotations_vector) {
|
|
|
|
|
// Look for the expectation as a leading susbtring, because the actual
|
|
|
|
|
// string that dyld uses will have the contents of the
|
2016-11-07 09:01:20 -05:00
|
|
|
|
// DYLD_INSERT_LIBRARIES environment variable appended to it on OS X
|
|
|
|
|
// 10.10.
|
2015-08-07 13:59:45 -04:00
|
|
|
|
if (annotation.substr(0, expected_annotation.length()) ==
|
2014-10-17 13:47:02 -04:00
|
|
|
|
expected_annotation) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-07 13:59:45 -04:00
|
|
|
|
EXPECT_TRUE(found) << expected_annotation;
|
2014-10-17 13:47:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dyld exposes its error_string at least as far back as Mac OS X 10.4.
|
|
|
|
|
if (test_type_ == kCrashDyld) {
|
|
|
|
|
const char kExpectedAnnotation[] = "could not load inserted library";
|
|
|
|
|
size_t expected_annotation_length = strlen(kExpectedAnnotation);
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (const std::string& annotation : all_annotations_vector) {
|
|
|
|
|
// Look for the expectation as a leading substring, because the actual
|
2016-11-07 09:01:20 -05:00
|
|
|
|
// string will contain the library’s pathname and, on OS X 10.9 and
|
|
|
|
|
// later, a reason.
|
2014-10-17 13:47:02 -04:00
|
|
|
|
if (annotation.substr(0, expected_annotation_length) ==
|
|
|
|
|
kExpectedAnnotation) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-07 13:59:45 -04:00
|
|
|
|
EXPECT_TRUE(found) << kExpectedAnnotation;
|
2014-10-17 13:47:02 -04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-04 14:29:12 -04:00
|
|
|
|
ExcServerCopyState(
|
|
|
|
|
behavior, old_state, old_state_count, new_state, new_state_count);
|
|
|
|
|
return ExcServerSuccessfulReturnValue(exception, behavior, false);
|
2014-10-17 13:47:02 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// MachMultiprocess:
|
|
|
|
|
|
|
|
|
|
void MachMultiprocessParent() override {
|
|
|
|
|
ProcessReader process_reader;
|
|
|
|
|
ASSERT_TRUE(process_reader.Initialize(ChildTask()));
|
|
|
|
|
|
|
|
|
|
// Wait for the child process to indicate that it’s done setting up its
|
|
|
|
|
// annotations via the CrashpadInfo interface.
|
|
|
|
|
char c;
|
2015-01-28 14:49:42 -08:00
|
|
|
|
CheckedReadFile(ReadPipeHandle(), &c, sizeof(c));
|
2014-10-17 13:47:02 -04:00
|
|
|
|
|
|
|
|
|
// Verify the “simple map” annotations set via the CrashpadInfo interface.
|
|
|
|
|
const std::vector<ProcessReader::Module>& modules =
|
|
|
|
|
process_reader.Modules();
|
|
|
|
|
std::map<std::string, std::string> all_annotations_simple_map;
|
|
|
|
|
for (const ProcessReader::Module& module : modules) {
|
|
|
|
|
MachOImageAnnotationsReader module_annotations_reader(
|
|
|
|
|
&process_reader, module.reader, module.name);
|
|
|
|
|
std::map<std::string, std::string> module_annotations_simple_map =
|
|
|
|
|
module_annotations_reader.SimpleMap();
|
|
|
|
|
all_annotations_simple_map.insert(module_annotations_simple_map.begin(),
|
|
|
|
|
module_annotations_simple_map.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EXPECT_GE(all_annotations_simple_map.size(), 5u);
|
|
|
|
|
EXPECT_EQ("crash", all_annotations_simple_map["#TEST# pad"]);
|
|
|
|
|
EXPECT_EQ("value", all_annotations_simple_map["#TEST# key"]);
|
|
|
|
|
EXPECT_EQ("y", all_annotations_simple_map["#TEST# x"]);
|
|
|
|
|
EXPECT_EQ("shorter", all_annotations_simple_map["#TEST# longer"]);
|
|
|
|
|
EXPECT_EQ("", all_annotations_simple_map["#TEST# empty_value"]);
|
|
|
|
|
|
|
|
|
|
// Tell the child process that it’s permitted to crash.
|
2015-01-28 14:49:42 -08:00
|
|
|
|
CheckedWriteFile(WritePipeHandle(), &c, sizeof(c));
|
2014-10-17 13:47:02 -04:00
|
|
|
|
|
|
|
|
|
if (test_type_ != kDontCrash) {
|
|
|
|
|
// Handle the child’s crash. Further validation will be done in
|
|
|
|
|
// CatchMachException().
|
2014-12-04 10:18:24 -05:00
|
|
|
|
UniversalMachExcServer universal_mach_exc_server(this);
|
|
|
|
|
|
2014-10-17 13:47:02 -04:00
|
|
|
|
mach_msg_return_t mr =
|
2014-12-04 10:18:24 -05:00
|
|
|
|
MachMessageServer::Run(&universal_mach_exc_server,
|
2014-10-17 13:47:02 -04:00
|
|
|
|
LocalPort(),
|
|
|
|
|
MACH_MSG_OPTION_NONE,
|
|
|
|
|
MachMessageServer::kOneShot,
|
2014-11-25 14:48:44 -05:00
|
|
|
|
MachMessageServer::kReceiveLargeError,
|
2014-12-10 11:11:21 -05:00
|
|
|
|
kMachMessageTimeoutWaitIndefinitely);
|
2014-10-17 13:47:02 -04:00
|
|
|
|
EXPECT_EQ(MACH_MSG_SUCCESS, mr)
|
|
|
|
|
<< MachErrorMessage(mr, "MachMessageServer::Run");
|
|
|
|
|
|
|
|
|
|
switch (test_type_) {
|
|
|
|
|
case kCrashAbort:
|
|
|
|
|
SetExpectedChildTermination(kTerminationSignal, SIGABRT);
|
|
|
|
|
break;
|
|
|
|
|
|
2015-08-07 13:59:45 -04:00
|
|
|
|
case kCrashModuleInitialization:
|
|
|
|
|
// This crash is triggered by __builtin_trap(), which shows up as
|
|
|
|
|
// SIGILL.
|
|
|
|
|
SetExpectedChildTermination(kTerminationSignal, SIGILL);
|
|
|
|
|
break;
|
|
|
|
|
|
2014-10-17 13:47:02 -04:00
|
|
|
|
case kCrashDyld:
|
2016-08-10 21:09:17 -04:00
|
|
|
|
// Prior to 10.12, dyld fatal errors result in the execution of an
|
|
|
|
|
// int3 instruction on x86 and a trap instruction on ARM, both of
|
|
|
|
|
// which raise SIGTRAP. 10.9.5 dyld-239.4/src/dyldStartup.s
|
|
|
|
|
// _dyld_fatal_error. This changed in 10.12 to use
|
|
|
|
|
// abort_with_payload(), which appears as SIGABRT to a waiting parent.
|
|
|
|
|
SetExpectedChildTermination(
|
|
|
|
|
kTerminationSignal,
|
|
|
|
|
MacOSXMinorVersion() < 12 ? SIGTRAP : SIGABRT);
|
2014-10-17 13:47:02 -04:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
FAIL();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MachMultiprocessChild() override {
|
|
|
|
|
CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo();
|
|
|
|
|
|
|
|
|
|
// This is “leaked” to crashpad_info.
|
|
|
|
|
SimpleStringDictionary* simple_annotations = new 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_info->set_simple_annotations(simple_annotations);
|
|
|
|
|
|
|
|
|
|
// Tell the parent that the environment has been set up.
|
|
|
|
|
char c = '\0';
|
2015-01-28 14:49:42 -08:00
|
|
|
|
CheckedWriteFile(WritePipeHandle(), &c, sizeof(c));
|
2014-10-17 13:47:02 -04:00
|
|
|
|
|
|
|
|
|
// Wait for the parent to indicate that it’s safe to crash.
|
2015-01-28 14:49:42 -08:00
|
|
|
|
CheckedReadFile(ReadPipeHandle(), &c, sizeof(c));
|
2014-10-17 13:47:02 -04:00
|
|
|
|
|
|
|
|
|
// Direct an exception message to the exception server running in the
|
|
|
|
|
// parent.
|
|
|
|
|
ExceptionPorts exception_ports(ExceptionPorts::kTargetTypeTask,
|
|
|
|
|
mach_task_self());
|
|
|
|
|
ASSERT_TRUE(exception_ports.SetExceptionPort(
|
|
|
|
|
EXC_MASK_CRASH, RemotePort(), EXCEPTION_DEFAULT, THREAD_STATE_NONE));
|
|
|
|
|
|
|
|
|
|
switch (test_type_) {
|
2015-08-07 13:59:45 -04:00
|
|
|
|
case kDontCrash: {
|
2014-10-17 13:47:02 -04:00
|
|
|
|
break;
|
2015-08-07 13:59:45 -04:00
|
|
|
|
}
|
2014-10-17 13:47:02 -04:00
|
|
|
|
|
2015-08-07 13:59:45 -04:00
|
|
|
|
case kCrashAbort: {
|
2014-10-17 13:47:02 -04:00
|
|
|
|
abort();
|
|
|
|
|
break;
|
2015-08-07 13:59:45 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case kCrashModuleInitialization: {
|
|
|
|
|
// Load a module that crashes while executing a module initializer.
|
|
|
|
|
void* dl_handle = dlopen(ModuleWithCrashyInitializer().c_str(),
|
|
|
|
|
RTLD_LAZY | RTLD_LOCAL);
|
|
|
|
|
|
|
|
|
|
// This should have crashed in the dlopen(). If dlopen() failed, the
|
|
|
|
|
// ASSERT_NE() will show the message. If it succeeded without crashing,
|
|
|
|
|
// the FAIL() will fail the test.
|
|
|
|
|
ASSERT_NE(nullptr, dl_handle) << dlerror();
|
|
|
|
|
FAIL();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-10-17 13:47:02 -04:00
|
|
|
|
|
|
|
|
|
case kCrashDyld: {
|
|
|
|
|
// Set DYLD_INSERT_LIBRARIES to contain a library that does not exist.
|
|
|
|
|
// Unable to load it, dyld will abort with a fatal error.
|
|
|
|
|
ASSERT_EQ(
|
|
|
|
|
0,
|
|
|
|
|
setenv(
|
|
|
|
|
"DYLD_INSERT_LIBRARIES", "/var/empty/NoDirectory/NoLibrary", 1))
|
|
|
|
|
<< ErrnoMessage("setenv");
|
|
|
|
|
|
|
|
|
|
// The actual executable doesn’t matter very much, because dyld won’t
|
|
|
|
|
// ever launch it. It just needs to be an executable that uses dyld as
|
2015-08-05 18:24:53 -04:00
|
|
|
|
// its LC_LOAD_DYLINKER (all normal executables do). A custom no-op
|
|
|
|
|
// executable is provided because DYLD_INSERT_LIBRARIES does not work
|
|
|
|
|
// with system executables on OS X 10.11 due to System Integrity
|
|
|
|
|
// Protection.
|
|
|
|
|
base::FilePath no_op_executable = NoOpExecutable();
|
|
|
|
|
ASSERT_EQ(0, execl(no_op_executable.value().c_str(),
|
|
|
|
|
no_op_executable.BaseName().value().c_str(),
|
|
|
|
|
nullptr))
|
2014-10-17 13:47:02 -04:00
|
|
|
|
<< ErrnoMessage("execl");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TestType test_type_;
|
|
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(TestMachOImageAnnotationsReader);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
TEST(MachOImageAnnotationsReader, DontCrash) {
|
|
|
|
|
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
|
|
|
|
|
TestMachOImageAnnotationsReader::kDontCrash);
|
|
|
|
|
test_mach_o_image_annotations_reader.Run();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(MachOImageAnnotationsReader, CrashAbort) {
|
|
|
|
|
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
|
|
|
|
|
TestMachOImageAnnotationsReader::kCrashAbort);
|
|
|
|
|
test_mach_o_image_annotations_reader.Run();
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-07 13:59:45 -04:00
|
|
|
|
TEST(MachOImageAnnotationsReader, CrashModuleInitialization) {
|
|
|
|
|
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
|
|
|
|
|
TestMachOImageAnnotationsReader::kCrashModuleInitialization);
|
|
|
|
|
test_mach_o_image_annotations_reader.Run();
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-17 13:47:02 -04:00
|
|
|
|
TEST(MachOImageAnnotationsReader, CrashDyld) {
|
|
|
|
|
TestMachOImageAnnotationsReader test_mach_o_image_annotations_reader(
|
|
|
|
|
TestMachOImageAnnotationsReader::kCrashDyld);
|
|
|
|
|
test_mach_o_image_annotations_reader.Run();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
} // namespace test
|
|
|
|
|
} // namespace crashpad
|