void onFault()

in cpp-ch/local-engine/Common/GlutenSignalHandler.cpp [241:375]


    void onFault(
        int sig, const siginfo_t & info, ucontext_t * context, const StackTrace & stack_trace, UInt32 thread_num, ThreadStatus * thread_ptr)
        const
    {
        String query_id;
        String query;

        /// Send logs from this thread to client if possible.
        /// It will allow client to see failure messages directly.
        if (thread_ptr)
        {
            query_id = thread_ptr->getQueryId();
            query = thread_ptr->getQueryForLog();

            if (auto logs_queue = thread_ptr->getInternalTextLogsQueue())
                CurrentThread::attachInternalTextLogsQueue(logs_queue, LogsLevel::trace);
        }
        std::string signal_description = "Unknown signal";

        /// Some of these are not really signals, but our own indications on failure reason.
        if (sig == StdTerminate)
            signal_description = "std::terminate";
        else if (sig == SanitizerTrap)
            signal_description = "sanitizer trap";
        else if (sig >= 0)
            signal_description = strsignal(sig); // NOLINT(concurrency-mt-unsafe) // it is not thread-safe but ok in this context

        LOG_FATAL(log, "########################################");

        if (query_id.empty())
        {
            LOG_FATAL(
                log,
                "(version {}{}, build id: {}, git hash: {}) (from thread {}) (no query) Received signal {} ({})",
                VERSION_STRING,
                VERSION_OFFICIAL,
                build_id,
                git_hash,
                thread_num,
                signal_description,
                sig);
        }
        else
        {
            LOG_FATAL(
                log,
                "(version {}{}, build id: {}, git hash: {}) (from thread {}) (query_id: {}) (query: {}) Received signal {} ({})",
                VERSION_STRING,
                VERSION_OFFICIAL,
                build_id,
                git_hash,
                thread_num,
                query_id,
                query,
                signal_description,
                sig);
        }
        String error_message;

        if (sig != SanitizerTrap)
            error_message = signalToErrorMessage(sig, info, *context);
        else
            error_message = "Sanitizer trap.";

        LOG_FATAL(log, fmt::runtime(error_message));

        /// Write symbolized stack trace line by line for better grep-ability.
        stack_trace.toStringEveryLine([this](std::string_view s) { LOG_FATAL(log, fmt::runtime(s)); });

#if defined(OS_LINUX)
        /// Write information about binary checksum. It can be difficult to calculate, so do it only after printing stack trace.
        /// TODO: Please keep the below log messages in-sync with the ones in ~programs/server/Server.cpp~

        if (stored_binary_hash.empty())
        {
            LOG_FATAL(log, "Integrity check of the executable skipped because the reference checksum could not be read.");
        }
        else
        {
            String calculated_binary_hash = getHashOfLoadedBinaryHex();
            if (calculated_binary_hash == stored_binary_hash)
            {
                LOG_FATAL(log, "Integrity check of the executable successfully passed (checksum: {})", calculated_binary_hash);
            }
            else
            {
                LOG_FATAL(
                    log,
                    "Calculated checksum of the executable ({0}) does not correspond"
                    " to the reference checksum stored in the executable ({1})."
                    " This may indicate one of the following:"
                    " - the executable was changed just after startup;"
                    " - the executable was corrupted on disk due to faulty hardware;"
                    " - the loaded executable was corrupted in memory due to faulty hardware;"
                    " - the file was intentionally modified;"
                    " - a logical error in the code.",
                    calculated_binary_hash,
                    stored_binary_hash);
            }
        }
#endif
        /// FIXME: Write crash to system.crash_log table if available.
        if (collectGlutenCrashLog)
            collectGlutenCrashLog(sig, thread_num, query_id, stack_trace);

        ///TODO: Send crash report to developers (if configured)
        if (sig != SanitizerTrap)
        {
            /// TODO: SentryWriter::onFault(sig, error_message, stack_trace);

            /// TODO:  Advice the user to send it manually.
        }
        /// ClickHouse Keeper does not link to some part of Settings.
#ifndef CLICKHOUSE_PROGRAM_STANDALONE_BUILD
        /// List changed settings.
        if (!query_id.empty())
        {
            ContextPtr query_context = thread_ptr->getQueryContext();
            if (query_context)
            {
                String changed_settings = query_context->getSettingsRef().toString();

                if (changed_settings.empty())
                    LOG_FATAL(log, "No settings were changed");
                else
                    LOG_FATAL(log, "Changed settings: {}", changed_settings);
            }
        }
#endif
        /// When everything is done, we will try to send these error messages to client.
        if (thread_ptr)
            thread_ptr->onFatalError();

        fatal_error_printed.test_and_set();
    }