mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 22:26:06 +00:00
This allows clients to use the database to handle uploads themselves, e.g. on Android, where Crashpad does not yet provide an uploader. The handler does not launch an upload thread when no url is supplied. Previously, the handler would move these reports to completed and record the upload as skipped with kUploadsDisabled. With this change, these reports would remain pending until pruned, with no metrics recorded for them in regard to their upload. Bug: crashpad:30 Change-Id: I4167ab1531634b10e91d03229018ae6aab4103aa Reviewed-on: https://chromium-review.googlesource.com/1010970 Reviewed-by: Robert Sesek <rsesek@chromium.org> Commit-Queue: Joshua Peraza <jperaza@chromium.org>
143 lines
4.7 KiB
C++
143 lines
4.7 KiB
C++
// Copyright 2017 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 <windows.h>
|
|
#include <dbghelp.h>
|
|
#include <string.h>
|
|
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "base/files/file_path.h"
|
|
#include "client/crash_report_database.h"
|
|
#include "client/crashpad_client.h"
|
|
#include "gtest/gtest.h"
|
|
#include "minidump/test/minidump_file_writer_test_util.h"
|
|
#include "test/test_paths.h"
|
|
#include "test/win/win_multiprocess_with_temp_dir.h"
|
|
#include "util/file/file_reader.h"
|
|
#include "util/misc/capture_context.h"
|
|
|
|
namespace crashpad {
|
|
namespace test {
|
|
namespace {
|
|
|
|
constexpr DWORD kExpectedExitCode = 0x1CEB00DA;
|
|
|
|
void StartAndCrashWithExtendedHandler(const base::FilePath& temp_dir) {
|
|
base::FilePath handler_path = TestPaths::BuildArtifact(
|
|
L"handler", L"extended_handler", TestPaths::FileType::kExecutable);
|
|
|
|
CrashpadClient client;
|
|
ASSERT_TRUE(client.StartHandler(handler_path,
|
|
temp_dir,
|
|
base::FilePath(),
|
|
"",
|
|
std::map<std::string, std::string>(),
|
|
std::vector<std::string>(),
|
|
false,
|
|
false));
|
|
|
|
// It appears that the GoogleTest fixture will catch and handle exceptions
|
|
// from here. Hence the fabricated crash in favor of raising an exception.
|
|
EXCEPTION_RECORD exception_record = {kExpectedExitCode,
|
|
EXCEPTION_NONCONTINUABLE};
|
|
CONTEXT context;
|
|
CaptureContext(&context);
|
|
EXCEPTION_POINTERS exception_pointers = {&exception_record, &context};
|
|
CrashpadClient::DumpAndCrash(&exception_pointers);
|
|
}
|
|
|
|
class CrashWithExtendedHandler final : public WinMultiprocessWithTempDir {
|
|
public:
|
|
CrashWithExtendedHandler() : WinMultiprocessWithTempDir() {}
|
|
~CrashWithExtendedHandler() {}
|
|
|
|
private:
|
|
void ValidateGeneratedDump();
|
|
|
|
void WinMultiprocessParent() override {
|
|
SetExpectedChildExitCode(kExpectedExitCode);
|
|
}
|
|
|
|
void WinMultiprocessChild() override {
|
|
StartAndCrashWithExtendedHandler(GetTempDirPath());
|
|
}
|
|
|
|
void WinMultiprocessParentAfterChild(HANDLE child) override {
|
|
// At this point the child has exited, which means the crash report should
|
|
// have been written.
|
|
ValidateGeneratedDump();
|
|
|
|
// Delegate the cleanup to the superclass.
|
|
WinMultiprocessWithTempDir::WinMultiprocessParentAfterChild(child);
|
|
}
|
|
};
|
|
|
|
void CrashWithExtendedHandler::ValidateGeneratedDump() {
|
|
// Open the database and find the sole dump that should have been created.
|
|
std::unique_ptr<CrashReportDatabase> database(
|
|
CrashReportDatabase::Initialize(GetTempDirPath()));
|
|
ASSERT_TRUE(database);
|
|
|
|
std::vector<CrashReportDatabase::Report> reports;
|
|
ASSERT_EQ(database->GetPendingReports(&reports),
|
|
CrashReportDatabase::kNoError);
|
|
ASSERT_EQ(reports.size(), 1u);
|
|
|
|
// Open the dump and validate that it has the extension stream with the
|
|
// expected contents.
|
|
FileReader reader;
|
|
ASSERT_TRUE(reader.Open(reports[0].file_path));
|
|
|
|
// Read the header.
|
|
MINIDUMP_HEADER header = {};
|
|
ASSERT_TRUE(reader.ReadExactly(&header, sizeof(header)));
|
|
|
|
// Read the directory.
|
|
std::vector<MINIDUMP_DIRECTORY> directory(header.NumberOfStreams);
|
|
ASSERT_TRUE(reader.SeekSet(header.StreamDirectoryRva));
|
|
ASSERT_TRUE(reader.ReadExactly(directory.data(),
|
|
directory.size() * sizeof(directory[0])));
|
|
|
|
// Search for the extension stream.
|
|
size_t found_extension_streams = 0;
|
|
for (const auto& entry : directory) {
|
|
if (entry.StreamType == 0xCAFEBABE) {
|
|
++found_extension_streams;
|
|
|
|
ASSERT_TRUE(reader.SeekSet(entry.Location.Rva));
|
|
|
|
std::vector<char> data;
|
|
data.resize(entry.Location.DataSize);
|
|
|
|
ASSERT_TRUE(reader.ReadExactly(data.data(), data.size()));
|
|
|
|
static constexpr char kExpectedData[] = "Injected extension stream!";
|
|
EXPECT_EQ(memcmp(kExpectedData, data.data(), sizeof(kExpectedData)), 0);
|
|
}
|
|
}
|
|
|
|
EXPECT_EQ(found_extension_streams, 1u);
|
|
}
|
|
|
|
TEST(CrashpadHandler, ExtensibilityCalloutsWork) {
|
|
WinMultiprocessWithTempDir::Run<CrashWithExtendedHandler>();
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace test
|
|
} // namespace crashpad
|