aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/breakpad/src/client/linux/handler/exception_trap.cc
blob: ef4146e43d196b62aa1225b7a9ae26929682295b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include "exception_trap.h"

#include <cstdlib>
#include <cstring>

#include <string>
#include <typeinfo>

namespace google_breakpad {

// ExceptionDescriptor

void ExceptionDescriptor::initialize(const char* type_name, const char* message) noexcept {
    std::strncpy(type_name_.data(), type_name, type_name_.size() - 1);
    std::strncpy(message_.data(), message, message_.size() - 1);
}

bool ExceptionDescriptor::isEmpty() const noexcept {
    return message_[0] == '\0' && type_name_[0] == '\0';
}

const char* ExceptionDescriptor::getTypeName() const noexcept {
    return type_name_.data();
}

const char* ExceptionDescriptor::getMessage() const noexcept {
    return message_.data();
}

// ExceptionTrap

bool ExceptionTrap::initializeOnce(const char* type_name, const char* message) noexcept {
    if (!initialized_.test_and_set()) {
        descriptor_.initialize(type_name, message);
        return true;
    }

    return false;
}

ExceptionTrap& ExceptionTrap::getInstance() noexcept {
    static ExceptionTrap instance{};

    return instance;
}

void ExceptionTrap::setupTerminateHandler() {
    getInstance().original_terminate_handler_ = std::set_terminate(
        ExceptionTrap::terminate_handler);
}

const ExceptionDescriptor& ExceptionTrap::getCurrentException() const noexcept {
    return descriptor_;
}

[[ noreturn ]] void ExceptionTrap::terminate() const noexcept(detail::can_catch_within_noexcept) {
    if(original_terminate_handler_ != nullptr) {
        try {
            original_terminate_handler_();
        } catch (...) {} // suppress all exceptions to avoid terminate recursion
    }
    std::abort();
}

[[ noreturn ]] void ExceptionTrap::terminate_handler() noexcept(detail::can_catch_within_noexcept) {
    try {
        const auto& e_ptr = std::current_exception(); // can throw bad_alloc

        if (e_ptr != nullptr) {
            std::rethrow_exception(e_ptr);
        }
    } catch (const std::exception& e) {
        getInstance().initializeOnce(typeid(e).name(), e.what());
    } catch (const std::string& e) {
        getInstance().initializeOnce(typeid(e).name(), e.c_str());
    } catch (const char* e) {
        getInstance().initializeOnce(typeid(e).name(), e);
    } catch (...) {
        getInstance().initializeOnce("Unknown", "Unknown");
    }

    getInstance().terminate();
}

} //namespace google_breakpad