Commit 12ecebb5 authored by Joshua Peraza's avatar Joshua Peraza Committed by Commit Bot

Update Crashpad to 640b13f3cb8000d361547f4cfa59275df44d1dc8

5368dc638901 handle potentially throwing functions in no_cfi_icall
cdb1e7f52bdc fix flake in LogOutputStreamTest
640b13f3cb80 linux: Don't load section headers of test module

Change-Id: I4e7f5d3983e499a20988fd1a3f6ca184ec4d1cf8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2500319
Commit-Queue: Mark Mentovai <mark@chromium.org>
Auto-Submit: Joshua Peraza <jperaza@chromium.org>
Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Cr-Commit-Position: refs/heads/master@{#821291}
parent b206b442
...@@ -2,7 +2,7 @@ Name: Crashpad ...@@ -2,7 +2,7 @@ Name: Crashpad
Short Name: crashpad Short Name: crashpad
URL: https://crashpad.chromium.org/ URL: https://crashpad.chromium.org/
Version: unknown Version: unknown
Revision: 71e8ec79870b5d7fe54327180f00c9dd26688280 Revision: 640b13f3cb8000d361547f4cfa59275df44d1dc8
License: Apache 2.0 License: Apache 2.0
License File: crashpad/LICENSE License File: crashpad/LICENSE
Security Critical: yes Security Critical: yes
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <utility> #include <utility>
#include "base/logging.h" #include "base/logging.h"
#include "build/build_config.h"
#include "client/settings.h" #include "client/settings.h"
#include "handler/linux/capture_snapshot.h" #include "handler/linux/capture_snapshot.h"
#include "minidump/minidump_file_writer.h" #include "minidump/minidump_file_writer.h"
...@@ -35,15 +36,53 @@ ...@@ -35,15 +36,53 @@
#include "util/stream/log_output_stream.h" #include "util/stream/log_output_stream.h"
#include "util/stream/zlib_output_stream.h" #include "util/stream/zlib_output_stream.h"
namespace crashpad { #if defined(OS_ANDROID)
#include <android/log.h>
#endif
namespace crashpad {
namespace { namespace {
class Logger : public LogOutputStream::Delegate {
public:
Logger() = default;
~Logger() = default;
#if defined(OS_ANDROID)
int Log(const char* buf) override {
return __android_log_buf_write(
LOG_ID_CRASH, ANDROID_LOG_FATAL, "crashpad", buf);
}
size_t OutputCap() override {
// Most minidumps are expected to be compressed and encoded into less than
// 128k.
return 128 * 1024;
}
size_t LineWidth() override {
// From Android NDK r20 <android/log.h>, log message text may be truncated
// to less than an implementation-specific limit (1023 bytes), for sake of
// safe and being easy to read in logcat, choose 512.
return 512;
}
#else
// TODO(jperaza): Log to an appropriate location on Linux.
int Log(const char* buf) override { return -ENOTCONN; }
size_t OutputCap() override { return 0; }
size_t LineWidth() override { return 0; }
#endif
private:
DISALLOW_COPY_AND_ASSIGN(Logger);
};
bool WriteMinidumpLogFromFile(FileReaderInterface* file_reader) { bool WriteMinidumpLogFromFile(FileReaderInterface* file_reader) {
ZlibOutputStream stream(ZlibOutputStream::Mode::kCompress, ZlibOutputStream stream(
std::make_unique<Base94OutputStream>( ZlibOutputStream::Mode::kCompress,
Base94OutputStream::Mode::kEncode, std::make_unique<Base94OutputStream>(
std::make_unique<LogOutputStream>())); Base94OutputStream::Mode::kEncode,
std::make_unique<LogOutputStream>(std::make_unique<Logger>())));
FileOperationResult read_result; FileOperationResult read_result;
do { do {
uint8_t buffer[4096]; uint8_t buffer[4096];
...@@ -259,7 +298,7 @@ bool CrashReportExceptionHandler::WriteMinidumpToLog( ...@@ -259,7 +298,7 @@ bool CrashReportExceptionHandler::WriteMinidumpToLog(
ZlibOutputStream::Mode::kCompress, ZlibOutputStream::Mode::kCompress,
std::make_unique<Base94OutputStream>( std::make_unique<Base94OutputStream>(
Base94OutputStream::Mode::kEncode, Base94OutputStream::Mode::kEncode,
std::make_unique<LogOutputStream>()))); std::make_unique<LogOutputStream>(std::make_unique<Logger>()))));
if (!minidump.WriteMinidump(&writer, false /* allow_seek */)) { if (!minidump.WriteMinidump(&writer, false /* allow_seek */)) {
LOG(ERROR) << "WriteMinidump failed"; LOG(ERROR) << "WriteMinidump failed";
return false; return false;
......
...@@ -643,16 +643,16 @@ bool WriteTestModule(const base::FilePath& module_path, ...@@ -643,16 +643,16 @@ bool WriteTestModule(const base::FilePath& module_path,
module.phdr_table.load1.p_type = PT_LOAD; module.phdr_table.load1.p_type = PT_LOAD;
module.phdr_table.load1.p_offset = 0; module.phdr_table.load1.p_offset = 0;
module.phdr_table.load1.p_vaddr = 0; module.phdr_table.load1.p_vaddr = 0;
module.phdr_table.load1.p_filesz = sizeof(module); module.phdr_table.load1.p_filesz = offsetof(decltype(module), shdr_table);
module.phdr_table.load1.p_memsz = sizeof(module); module.phdr_table.load1.p_memsz = offsetof(decltype(module), shdr_table);
module.phdr_table.load1.p_flags = PF_R; module.phdr_table.load1.p_flags = PF_R;
module.phdr_table.load1.p_align = load2_vaddr; module.phdr_table.load1.p_align = load2_vaddr;
module.phdr_table.load2.p_type = PT_LOAD; module.phdr_table.load2.p_type = PT_LOAD;
module.phdr_table.load2.p_offset = 0; module.phdr_table.load2.p_offset = 0;
module.phdr_table.load2.p_vaddr = load2_vaddr; module.phdr_table.load2.p_vaddr = load2_vaddr;
module.phdr_table.load2.p_filesz = sizeof(module); module.phdr_table.load2.p_filesz = offsetof(decltype(module), shdr_table);
module.phdr_table.load2.p_memsz = sizeof(module); module.phdr_table.load2.p_memsz = offsetof(decltype(module), shdr_table);
module.phdr_table.load2.p_flags = PF_R | PF_W; module.phdr_table.load2.p_flags = PF_R | PF_W;
module.phdr_table.load2.p_align = load2_vaddr; module.phdr_table.load2.p_align = load2_vaddr;
......
...@@ -76,6 +76,28 @@ struct FunctorTraits<R(__stdcall*)(Args...) noexcept> { ...@@ -76,6 +76,28 @@ struct FunctorTraits<R(__stdcall*)(Args...) noexcept> {
}; };
#endif // OS_WIN && ARCH_CPU_X86 #endif // OS_WIN && ARCH_CPU_X86
#if __cplusplus >= 201703L
// These specializations match functions which are not explicitly declared
// noexcept. They must only be present at C++17 when noexcept is part of a
// function's type. If they are present earlier, they redefine the
// specializations above.
template <typename R, typename... Args>
struct FunctorTraits<R (*)(Args...)> {
template <typename Function, typename... RunArgs>
DISABLE_CFI_ICALL static R Invoke(Function&& function, RunArgs&&... args) {
return std::forward<Function>(function)(std::forward<RunArgs>(args)...);
}
};
template <typename R, typename... Args>
struct FunctorTraits<R (*)(Args..., ...)> {
template <typename Function, typename... RunArgs>
DISABLE_CFI_ICALL static R Invoke(Function&& function, RunArgs&&... args) {
return std::forward<Function>(function)(std::forward<RunArgs>(args)...);
}
};
#endif
} // namespace } // namespace
//! \brief Disables cfi-icall for calls made through a function pointer. //! \brief Disables cfi-icall for calls made through a function pointer.
......
...@@ -21,27 +21,14 @@ ...@@ -21,27 +21,14 @@
#include "base/check.h" #include "base/check.h"
#include "base/logging.h" #include "base/logging.h"
#if defined(OS_ANDROID)
#include <android/log.h>
#endif
namespace crashpad { namespace crashpad {
namespace { LogOutputStream::LogOutputStream(std::unique_ptr<Delegate> delegate)
: delegate_(std::move(delegate)),
// Most minidumps are expected to be compressed and encoded into less than 128k. output_count_(0),
constexpr size_t kOutputCap = 128 * 1024; flush_needed_(false),
flushed_(false) {
// From Android NDK r20 <android/log.h>, log message text may be truncated to buffer_.reserve(delegate_->LineWidth());
// less than an implementation-specific limit (1023 bytes), for sake of safe
// and being easy to read in logcat, choose 512.
constexpr size_t kLineBufferSize = 512;
} // namespace
LogOutputStream::LogOutputStream()
: output_count_(0), flush_needed_(false), flushed_(false) {
buffer_.reserve(kLineBufferSize);
} }
LogOutputStream::~LogOutputStream() { LogOutputStream::~LogOutputStream() {
...@@ -50,17 +37,19 @@ LogOutputStream::~LogOutputStream() { ...@@ -50,17 +37,19 @@ LogOutputStream::~LogOutputStream() {
bool LogOutputStream::Write(const uint8_t* data, size_t size) { bool LogOutputStream::Write(const uint8_t* data, size_t size) {
DCHECK(!flushed_); DCHECK(!flushed_);
static constexpr char kBeginMessage[] = "-----BEGIN CRASHPAD MINIDUMP-----";
if (output_count_ == 0 && WriteToLog(kBeginMessage) < 0) {
return false;
}
flush_needed_ = true; flush_needed_ = true;
while (size > 0) { while (size > 0) {
size_t m = std::min(kLineBufferSize - buffer_.size(), size); size_t m = std::min(delegate_->LineWidth() - buffer_.size(), size);
buffer_.append(reinterpret_cast<const char*>(data), m); buffer_.append(reinterpret_cast<const char*>(data), m);
data += m; data += m;
size -= m; size -= m;
if (buffer_.size() == kLineBufferSize && !WriteBuffer()) { if (buffer_.size() == delegate_->LineWidth() && !WriteBuffer()) {
flush_needed_ = false;
LOG(ERROR) << "Write: exceeds cap.";
if (output_stream_for_testing_)
output_stream_for_testing_->Flush();
return false; return false;
} }
} }
...@@ -68,66 +57,47 @@ bool LogOutputStream::Write(const uint8_t* data, size_t size) { ...@@ -68,66 +57,47 @@ bool LogOutputStream::Write(const uint8_t* data, size_t size) {
} }
bool LogOutputStream::WriteBuffer() { bool LogOutputStream::WriteBuffer() {
if (output_count_ == 0) {
if (!WriteToLog("-----BEGIN CRASHPAD MINIDUMP-----"))
return false;
}
if (buffer_.empty()) if (buffer_.empty())
return true; return true;
static constexpr char kAbortMessage[] = "-----ABORT CRASHPAD MINIDUMP-----";
output_count_ += buffer_.size(); output_count_ += buffer_.size();
if (output_count_ > kOutputCap) { if (output_count_ > delegate_->OutputCap()) {
WriteToLog("-----ABORT CRASHPAD MINIDUMP-----"); WriteToLog(kAbortMessage);
flush_needed_ = false;
return false; return false;
} }
bool result = WriteToLog(buffer_.c_str()); int result = WriteToLog(buffer_.c_str());
buffer_.clear(); if (result < 0) {
return result; if (result == -EAGAIN) {
} WriteToLog(kAbortMessage);
}
bool LogOutputStream::WriteToLog(const char* buf) { flush_needed_ = false;
#if defined(OS_ANDROID)
int ret =
__android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, "crashpad", buf);
if (ret < 0) {
errno = -ret;
PLOG(ERROR) << "__android_log_buf_write";
return false; return false;
} }
#endif
// For testing. buffer_.clear();
if (output_stream_for_testing_) {
return output_stream_for_testing_->Write(
reinterpret_cast<const uint8_t*>(buf), strlen(buf));
}
return true; return true;
} }
bool LogOutputStream::Flush() { int LogOutputStream::WriteToLog(const char* buf) {
flush_needed_ = false; return delegate_->Log(buf);
flushed_ = true; }
bool LogOutputStream::Flush() {
bool result = true; bool result = true;
if (WriteBuffer()) { if (flush_needed_) {
result = WriteToLog("-----END CRASHPAD MINIDUMP-----"); flush_needed_ = false;
} else { flushed_ = true;
LOG(ERROR) << "Flush: exceeds cap.";
result = false;
}
// Since output_stream_for_testing_'s Write() method has been called, its
// Flush() shall always be invoked.
if (output_stream_for_testing_)
output_stream_for_testing_->Flush();
static constexpr char kEndMessage[] = "-----END CRASHPAD MINIDUMP-----";
if (!WriteBuffer() || WriteToLog(kEndMessage) < 0) {
result = false;
}
}
return result; return result;
} }
void LogOutputStream::SetOutputStreamForTesting(
std::unique_ptr<OutputStreamInterface> stream) {
output_stream_for_testing_ = std::move(stream);
}
} // namespace crashpad } // namespace crashpad
...@@ -26,32 +26,48 @@ ...@@ -26,32 +26,48 @@
namespace crashpad { namespace crashpad {
//! \brief This class output the received data to Android log, NOP in other //! \brief This class outputs a stream of data as a series of log messages.
//! platform.
//!
//! To avoid overflowing Android log, total 128k log data is allowed, after
//! that cap, the output is aborted.
class LogOutputStream : public OutputStreamInterface { class LogOutputStream : public OutputStreamInterface {
public: public:
LogOutputStream(); //! \brief An interface to a log output sink.
class Delegate {
public:
Delegate() = default;
virtual ~Delegate() = default;
//! \brief Logs |buf| to the output sink.
//!
//! \param buf the buffer to write to the log. More bytes than are in |buf|
//! may be written, e.g. to convey metadata.
//! \return the number of bytes written, or a negative error code.
virtual int Log(const char* buf) = 0;
//! \brief Returns the maximum number of bytes to allow writing to this log.
virtual size_t OutputCap() = 0;
//! \brief Returns the maximum length of buffers allowed to be passed to
//! Log().
virtual size_t LineWidth() = 0;
};
LogOutputStream(std::unique_ptr<Delegate> delegate);
~LogOutputStream() override; ~LogOutputStream() override;
// OutputStreamInterface: // OutputStreamInterface:
bool Write(const uint8_t* data, size_t size) override; bool Write(const uint8_t* data, size_t size) override;
bool Flush() override; bool Flush() override;
void SetOutputStreamForTesting(std::unique_ptr<OutputStreamInterface> stream);
private: private:
// Flush the |buffer_|, return false if kOutputCap meet. // Flushes buffer_, returning false on failure.
bool WriteBuffer(); bool WriteBuffer();
bool WriteToLog(const char* buf);
int WriteToLog(const char* buf);
std::string buffer_; std::string buffer_;
std::unique_ptr<Delegate> delegate_;
size_t output_count_; size_t output_count_;
bool flush_needed_; bool flush_needed_;
bool flushed_; bool flushed_;
std::unique_ptr<OutputStreamInterface> output_stream_for_testing_;
DISALLOW_COPY_AND_ASSIGN(LogOutputStream); DISALLOW_COPY_AND_ASSIGN(LogOutputStream);
}; };
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "base/macros.h" #include "base/macros.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "util/stream/test_output_stream.h"
namespace crashpad { namespace crashpad {
namespace test { namespace test {
...@@ -32,21 +31,34 @@ const char* kBeginGuard = "-----BEGIN CRASHPAD MINIDUMP-----"; ...@@ -32,21 +31,34 @@ const char* kBeginGuard = "-----BEGIN CRASHPAD MINIDUMP-----";
const char* kEndGuard = "-----END CRASHPAD MINIDUMP-----"; const char* kEndGuard = "-----END CRASHPAD MINIDUMP-----";
const char* kAbortGuard = "-----ABORT CRASHPAD MINIDUMP-----"; const char* kAbortGuard = "-----ABORT CRASHPAD MINIDUMP-----";
std::string ConvertToString(const std::vector<uint8_t>& src) { class LogOutputStreamTestDelegate : public LogOutputStream::Delegate {
return std::string(reinterpret_cast<const char*>(src.data()), src.size()); public:
} LogOutputStreamTestDelegate(std::string* logging_destination)
: logging_destination_(logging_destination) {}
~LogOutputStreamTestDelegate() = default;
int Log(const char* buf) override {
size_t len = strnlen(buf, kLineBufferSize + 1);
EXPECT_LE(len, kLineBufferSize);
logging_destination_->append(buf, len);
return static_cast<int>(len);
}
size_t OutputCap() override { return kOutputCap; }
size_t LineWidth() override { return kLineBufferSize; }
private:
std::string* logging_destination_;
};
class LogOutputStreamTest : public testing::Test { class LogOutputStreamTest : public testing::Test {
public: public:
LogOutputStreamTest() : test_output_stream_(nullptr) {} LogOutputStreamTest() : test_log_output_() {}
protected: protected:
void SetUp() override { void SetUp() override {
std::unique_ptr<TestOutputStream> output_stream = log_stream_ = std::make_unique<LogOutputStream>(
std::make_unique<TestOutputStream>(); std::make_unique<LogOutputStreamTestDelegate>(&test_log_output_));
test_output_stream_ = output_stream.get();
log_stream_ = std::make_unique<LogOutputStream>();
log_stream_->SetOutputStreamForTesting(std::move(output_stream));
} }
const uint8_t* BuildDeterministicInput(size_t size) { const uint8_t* BuildDeterministicInput(size_t size) {
...@@ -57,37 +69,25 @@ class LogOutputStreamTest : public testing::Test { ...@@ -57,37 +69,25 @@ class LogOutputStreamTest : public testing::Test {
return deterministic_input_base; return deterministic_input_base;
} }
TestOutputStream* test_output_stream() const { return test_output_stream_; } const std::string& test_log_output() const { return test_log_output_; }
LogOutputStream* log_stream() const { return log_stream_.get(); } LogOutputStream* log_stream() const { return log_stream_.get(); }
private: private:
std::unique_ptr<LogOutputStream> log_stream_; std::unique_ptr<LogOutputStream> log_stream_;
TestOutputStream* test_output_stream_; std::string test_log_output_;
std::unique_ptr<uint8_t[]> deterministic_input_; std::unique_ptr<uint8_t[]> deterministic_input_;
DISALLOW_COPY_AND_ASSIGN(LogOutputStreamTest); DISALLOW_COPY_AND_ASSIGN(LogOutputStreamTest);
}; };
TEST_F(LogOutputStreamTest, VerifyGuards) {
log_stream()->Flush();
// Verify OutputStream wrote 2 guards.
EXPECT_EQ(test_output_stream()->write_count(), 2u);
EXPECT_EQ(test_output_stream()->flush_count(), 1u);
EXPECT_FALSE(test_output_stream()->all_data().empty());
EXPECT_EQ(ConvertToString(test_output_stream()->all_data()),
std::string(kBeginGuard).append(kEndGuard));
}
TEST_F(LogOutputStreamTest, WriteShortLog) { TEST_F(LogOutputStreamTest, WriteShortLog) {
const uint8_t* input = BuildDeterministicInput(2); const uint8_t* input = BuildDeterministicInput(2);
EXPECT_TRUE(log_stream()->Write(input, 2)); EXPECT_TRUE(log_stream()->Write(input, 2));
EXPECT_TRUE(log_stream()->Flush()); EXPECT_TRUE(log_stream()->Flush());
// Verify OutputStream wrote 2 guards and data. // Verify OutputStream wrote 2 guards and data.
EXPECT_EQ(test_output_stream()->write_count(), 3u); EXPECT_FALSE(test_log_output().empty());
EXPECT_EQ(test_output_stream()->flush_count(), 1u); EXPECT_EQ(test_log_output(),
EXPECT_FALSE(test_output_stream()->all_data().empty());
EXPECT_EQ(ConvertToString(test_output_stream()->all_data()),
std::string(kBeginGuard).append("aa").append(kEndGuard)); std::string(kBeginGuard).append("aa").append(kEndGuard));
} }
...@@ -97,10 +97,7 @@ TEST_F(LogOutputStreamTest, WriteLongLog) { ...@@ -97,10 +97,7 @@ TEST_F(LogOutputStreamTest, WriteLongLog) {
// Verify OutputStream wrote 2 guards and data. // Verify OutputStream wrote 2 guards and data.
EXPECT_TRUE(log_stream()->Write(input, input_length)); EXPECT_TRUE(log_stream()->Write(input, input_length));
EXPECT_TRUE(log_stream()->Flush()); EXPECT_TRUE(log_stream()->Flush());
EXPECT_EQ(test_output_stream()->write_count(), EXPECT_EQ(test_log_output().size(),
2 + input_length / kLineBufferSize + 1);
EXPECT_EQ(test_output_stream()->flush_count(), 1u);
EXPECT_EQ(test_output_stream()->all_data().size(),
strlen(kBeginGuard) + strlen(kEndGuard) + input_length); strlen(kBeginGuard) + strlen(kEndGuard) + input_length);
} }
...@@ -108,17 +105,19 @@ TEST_F(LogOutputStreamTest, WriteAbort) { ...@@ -108,17 +105,19 @@ TEST_F(LogOutputStreamTest, WriteAbort) {
size_t input_length = kOutputCap + kLineBufferSize; size_t input_length = kOutputCap + kLineBufferSize;
const uint8_t* input = BuildDeterministicInput(input_length); const uint8_t* input = BuildDeterministicInput(input_length);
EXPECT_FALSE(log_stream()->Write(input, input_length)); EXPECT_FALSE(log_stream()->Write(input, input_length));
std::string data(ConvertToString(test_output_stream()->all_data())); EXPECT_EQ(
EXPECT_EQ(data.substr(data.size() - strlen(kAbortGuard)), kAbortGuard); test_log_output().substr(test_log_output().size() - strlen(kAbortGuard)),
kAbortGuard);
} }
TEST_F(LogOutputStreamTest, FlushAbort) { TEST_F(LogOutputStreamTest, FlushAbort) {
size_t input_length = kOutputCap + kLineBufferSize / 2; size_t input_length = kOutputCap - strlen(kBeginGuard) + kLineBufferSize / 2;
const uint8_t* input = BuildDeterministicInput(input_length); const uint8_t* input = BuildDeterministicInput(input_length);
EXPECT_TRUE(log_stream()->Write(input, input_length)); EXPECT_TRUE(log_stream()->Write(input, input_length));
EXPECT_FALSE(log_stream()->Flush()); EXPECT_FALSE(log_stream()->Flush());
std::string data(ConvertToString(test_output_stream()->all_data())); EXPECT_EQ(
EXPECT_EQ(data.substr(data.size() - strlen(kAbortGuard)), kAbortGuard); test_log_output().substr(test_log_output().size() - strlen(kAbortGuard)),
kAbortGuard);
} }
} // namespace } // namespace
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment