bool PointerData::Initialize(const Config& config) NO_THREAD_SAFETY_ANALYSIS {
pointers_.clear();
key_to_index_.clear();
frames_.clear();
free_pointers_.clear(); // A hash index of kBacktraceEmptyIndex indicates that we tried to get // a backtrace, but there was nothing recorded.
cur_hash_index_ = kBacktraceEmptyIndex + 1;
backtrace_enabled_ = config.backtrace_enabled(); if (config.backtrace_enable_on_signal()) { struct sigaction64 enable_act = {};
enable_act.sa_sigaction = ToggleBacktraceEnable;
enable_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; if (sigaction64(config.backtrace_signal(), &enable_act, nullptr) != 0) {
error_log("Unable to set up backtrace signal enable function: %m"); returnfalse;
} if (config.options() & VERBOSE) {
info_log("%s: Run: 'kill -%d %d' to enable backtracing.", getprogname(),
config.backtrace_signal(), getpid());
}
}
if (config.options() & BACKTRACE) { struct sigaction64 act = {};
act.sa_sigaction = EnableDump;
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; if (sigaction64(config.backtrace_dump_signal(), &act, nullptr) != 0) {
error_log("Unable to set up backtrace dump signal function: %m"); returnfalse;
} if (config.options() & VERBOSE) {
info_log("%s: Run: 'kill -%d %d' to dump the backtrace.", getprogname(),
config.backtrace_dump_signal(), getpid());
}
}
backtrace_dump_ = false;
if (config.options() & FREE_TRACK) {
g_cmp_mem.resize(kCompareBufferSize, config.fill_free_value());
} returntrue;
}
void PointerData::LogBacktrace(size_t hash_index) {
std::lock_guard<std::mutex> frame_guard(frame_mutex_); if (g_debug->config().options() & BACKTRACE_FULL) { auto backtrace_info_entry = backtraces_info_.find(hash_index); if (backtrace_info_entry != backtraces_info_.end()) {
UnwindLog(backtrace_info_entry->second); return;
}
} else { auto frame_entry = frames_.find(hash_index); if (frame_entry != frames_.end()) {
FrameInfoType* frame_info = &frame_entry->second;
backtrace_log(frame_info->frames.data(), frame_info->frames.size()); return;
}
}
error_log(" hash_index %zu does not have matching frame data.", hash_index);
}
void PointerData::LogFreeError(const FreePointerInfoType& info, size_t max_cmp_bytes) {
error_log(LOG_DIVIDER);
uintptr_t pointer = DemanglePointer(info.mangled_ptr);
uint8_t* memory = reinterpret_cast<uint8_t*>(pointer);
error_log("+++ ALLOCATION %p USED AFTER FREE", memory);
uint8_t fill_free_value = g_debug->config().fill_free_value(); for (size_t i = 0; i < max_cmp_bytes; i++) { if (memory[i] != fill_free_value) {
error_log(" allocation[%zu] = 0x%02x (expected 0x%02x)", i, memory[i], fill_free_value);
}
}
if (info.hash_index > kBacktraceEmptyIndex) {
error_log("Backtrace at time of free:");
LogBacktrace(info.hash_index);
}
error_log(LOG_DIVIDER); if (g_debug->config().options() & ABORT_ON_ERROR) {
abort();
}
}
void PointerData::VerifyFreedPointer(const FreePointerInfoType& info) {
size_t usable_size;
uintptr_t pointer = DemanglePointer(info.mangled_ptr); if (g_debug->HeaderEnabled()) { // Check to see if the tag data has been damaged.
Header* header = g_debug->GetHeader(reinterpret_cast<constvoid*>(pointer)); if (header->tag != DEBUG_FREE_TAG) {
error_log(LOG_DIVIDER);
error_log("+++ ALLOCATION 0x%" PRIxPTR " HAS CORRUPTED HEADER TAG 0x%x AFTER FREE", pointer,
header->tag);
error_log(LOG_DIVIDER); if (g_debug->config().options() & ABORT_ON_ERROR) {
abort();
}
// Stop processing here, it is impossible to tell how the header // may have been damaged. return;
}
usable_size = header->usable_size;
} else {
usable_size = g_dispatch->malloc_usable_size(reinterpret_cast<constvoid*>(pointer));
}
void PointerData::GetList(std::vector<ListInfoType>* list, bool only_with_backtrace)
REQUIRES(pointer_mutex_, frame_mutex_) { for (constauto& entry : pointers_) {
FrameInfoType* frame_info = nullptr;
std::vector<unwindstack::FrameData>* backtrace_info = nullptr;
uintptr_t pointer = DemanglePointer(entry.first);
size_t hash_index = entry.second.hash_index; if (hash_index > kBacktraceEmptyIndex) { auto frame_entry = frames_.find(hash_index); if (frame_entry == frames_.end()) { // Somehow wound up with a pointer with a valid hash_index, but // no frame data. This should not be possible since adding a pointer // occurs after the hash_index and frame data have been added. // When removing a pointer, the pointer is deleted before the frame // data.
error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", pointer, hash_index);
} else {
frame_info = &frame_entry->second;
}
if (g_debug->config().options() & BACKTRACE_FULL) { auto backtrace_entry = backtraces_info_.find(hash_index); if (backtrace_entry == backtraces_info_.end()) {
error_log("Pointer 0x%" PRIxPTR " hash_index %zu does not exist.", pointer, hash_index);
} else {
backtrace_info = &backtrace_entry->second;
}
}
} if (hash_index == 0 && only_with_backtrace) { continue;
}
// Put the pointers with longest backtrace first. if (a_frame->frames.size() != b_frame->frames.size()) { return a_frame->frames.size() > b_frame->frames.size();
}
// Last sort by pointer. return a.pointer < b.pointer;
});
}
size_t track_count = 0; for (constauto& list_info : list) {
error_log("+++ %s leaked block of size %zu at 0x%" PRIxPTR " (leak %zu of %zu)", getprogname(),
list_info.size, list_info.pointer, ++track_count, list.size()); if (list_info.backtrace_info != nullptr) {
error_log("Backtrace at time of allocation:");
UnwindLog(*list_info.backtrace_info);
} elseif (list_info.frame_info != nullptr) {
error_log("Backtrace at time of allocation:");
backtrace_log(list_info.frame_info->frames.data(), list_info.frame_info->frames.size());
} // Do not bother to free the pointers, we are about to exit any way.
}
}
void PointerData::PostForkChild() __attribute__((no_thread_safety_analysis)) { // Make sure that any potential mutexes have been released and are back // to an initial state.
frame_mutex_.try_lock();
frame_mutex_.unlock();
pointer_mutex_.try_lock();
pointer_mutex_.unlock();
free_pointer_mutex_.try_lock();
free_pointer_mutex_.unlock();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.