/
klischa
/
AstraScanner2
Обзор
Документация
Войти
/
klischa
/
AstraScanner2
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/main.cpp
233 строки
8 KB
k k
refactor: remove duplicate TopLevelMiniDump, use installCrashHandler from crash_handler.h
14 июл 2026, 22:27
14 июл 2026, 22:27
261b059
Код
Авторство
О чём код?
#include <QApplication> #include <QCoreApplication> #include <QFile> #include <QTextStream> #include <QDateTime> #include <QDir> #include <QFileInfo> #include <QSurfaceFormat> #include <QMetaObject> #include <QMutex> #include "crash_handler.h" #include <QException> #include <exception> #include <cstdlib> #include "gui/MainWindow.h" #include "settings/SettingsManager.h" #ifdef _WIN32 #include <windows.h> #include <dbghelp.h> #include <eh.h> #pragma comment(lib, "Dbghelp.lib") #endif static QFile g_logFile; static QMutex g_logMutex; // Для потокобезопасного доступа к файлу static bool g_exceptionCaught = false; // Флаг для предотвращения рекурсии // SEH translator для Windows - преобразует системные исключения в C++ исключения #ifdef _WIN32 void sehTranslator(unsigned int code, EXCEPTION_POINTERS* info) { QString errorMsg = QString::fromStdString(std::to_string(code)); switch (code) { case EXCEPTION_ACCESS_VIOLATION: errorMsg = "EXCEPTION_ACCESS_VIOLATION"; break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: errorMsg = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; break; case EXCEPTION_STACK_OVERFLOW: errorMsg = "EXCEPTION_STACK_OVERFLOW"; break; case EXCEPTION_ILLEGAL_INSTRUCTION: errorMsg = "EXCEPTION_ILLEGAL_INSTRUCTION"; break; default: break; } throw std::runtime_error("SEH exception (" + errorMsg.toStdString() + ")"); } // Глобальный перехватчик исключений void terminateHandler() { QMutexLocker locker(&g_logMutex); if (!g_exceptionCaught && g_logFile.isOpen()) { g_exceptionCaught = true; QTextStream out(&g_logFile); out << Qt::endl; out << "=== FATAL: Unhandled exception occurred ===" << Qt::endl; out << "Application is terminating due to unhandled exception" << Qt::endl; try { std::rethrow_if_nested(std::current_exception()); } catch (const std::exception& e) { out << "Exception type: " << typeid(e).name() << Qt::endl; out << "Exception message: " << e.what() << Qt::endl; } catch (...) { out << "Unknown exception type" << Qt::endl; } out.flush(); } std::abort(); } #endif void fileMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { Q_UNUSED(context); if (type == QtDebugMsg) return; QString level; switch (type) { case QtInfoMsg: level = "INFO"; break; case QtWarningMsg: level = "WARN"; break; case QtCriticalMsg: level = "CRIT"; break; case QtFatalMsg: level = "FATAL"; break; default: level = "LOG"; break; } QString formatted = QString("[%1] %2").arg(level, msg); QTextStream(stderr) << formatted << Qt::endl; { QMutexLocker locker(&g_logMutex); if (g_logFile.isOpen()) { QTextStream out(&g_logFile); out << formatted << Qt::endl; static QElapsedTimer flushTimer; static bool flushTimerStarted = false; if (!flushTimerStarted) { flushTimer.start(); flushTimerStarted = true; } if (type == QtFatalMsg || type == QtCriticalMsg || flushTimer.elapsed() > 2000) { out.flush(); flushTimer.restart(); } } } if (MainWindow *mw = g_mainWindow.load(std::memory_order_acquire)) { QMetaObject::invokeMethod(mw, "appendLog", Qt::QueuedConnection, Q_ARG(QString, formatted)); } } int main(int argc, char *argv[]) { #ifdef _WIN32 installCrashHandler(); _set_se_translator(sehTranslator); #endif // Устанавливаем глобальный перехватчик исключений #ifdef _WIN32 std::set_terminate(terminateHandler); #endif // Отключаем Media Foundation до того, как OpenCV VideoIO будет впервые // проинициализирован. Переменная обязана быть выставлена до первого // использования cv::VideoCapture. #ifdef _WIN32 _putenv("OPENCV_VIDEOIO_PRIORITY_MSMF=0"); #else setenv("OPENCV_VIDEOIO_PRIORITY_MSMF", "0", 1); #endif QSurfaceFormat fmt; fmt.setRenderableType(QSurfaceFormat::OpenGL); fmt.setVersion(3, 2); fmt.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(fmt); // QSettings читает эти поля — выставляем до создания QApplication, чтобы // SettingsManager из любого места мог полагаться на них. QCoreApplication::setOrganizationName("AstraScanner"); QCoreApplication::setOrganizationDomain("astra-scanner.local"); QCoreApplication::setApplicationName("AstraScanner"); QApplication app(argc, argv); // Регистрируем типы для cross-thread сигналов qRegisterMetaType<cv::Mat>("cv::Mat"); qRegisterMetaType<QSharedPointer<cv::Mat>>("QSharedPointer<cv::Mat>"); qRegisterMetaType<pcl::PointCloud<pcl::PointXYZRGB>::Ptr>("pcl::PointCloud<pcl::PointXYZRGB>::Ptr"); qRegisterMetaType<Eigen::Affine3f>("Eigen::Affine3f"); qRegisterMetaType<TrackingMode>("TrackingMode"); // Создаем singleton до начала event loop // Он будет уничтожен автоматически при выходе из main() SettingsManager& settings = SettingsManager::instance(); QDir().mkpath("logs"); // --- Ротация логов: если файл > 10 МБ, переименовать в .old --- { const QString logPath = "logs/scanner.log"; QFileInfo fi(logPath); if (fi.exists() && fi.size() > 10 * 1024 * 1024) { const QString oldPath = "logs/scanner.log.old"; QFile::remove(oldPath); QFile::rename(logPath, oldPath); } } g_logFile.setFileName("logs/scanner.log"); if (!g_logFile.open(QIODevice::Append | QIODevice::Text)) { QTextStream(stderr) << "Failed to open log file" << Qt::endl; } else { QTextStream out(&g_logFile); out << Qt::endl << "=== Session started at " << QDateTime::currentDateTime().toString() << " ===" << Qt::endl; out.flush(); } qInstallMessageHandler(fileMessageHandler); MainWindow w; g_mainWindow.store(&w, std::memory_order_release); w.show(); // Оборачиваем event loop в try-catch для перехвата всех исключений try { int result = app.exec(); // Сброс g_mainWindow ДО разрушения MainWindow. // Это гарантирует, что любой qDebug() из деструкторов не // попытается обратиться к dangling pointer через g_mainWindow. g_mainWindow.store(nullptr, std::memory_order_release); // Явное уничтожение singleton перед завершением QCoreApplication // Это предотвращает static destruction order fiasco SettingsManager::destroyInstance(); g_logFile.close(); return result; } catch (const std::exception& e) { QMutexLocker locker(&g_logMutex); if (g_logFile.isOpen()) { QTextStream out(&g_logFile); out << Qt::endl; out << "=== FATAL: std::exception caught in app.exec() ===" << Qt::endl; out << "Exception type: " << typeid(e).name() << Qt::endl; out << "Exception message: " << e.what() << Qt::endl; out.flush(); } QTextStream(stderr) << "std::exception caught: " << e.what() << Qt::endl; g_logFile.close(); SettingsManager::destroyInstance(); g_mainWindow.store(nullptr, std::memory_order_release); return -1; } catch (...) { QMutexLocker locker(&g_logMutex); if (g_logFile.isOpen()) { QTextStream out(&g_logFile); out << Qt::endl; out << "=== FATAL: Unknown exception caught in app.exec() ===" << Qt::endl; out << "Unknown exception type" << Qt::endl; out.flush(); } QTextStream(stderr) << "Unknown exception caught" << Qt::endl; g_logFile.close(); SettingsManager::destroyInstance(); g_mainWindow.store(nullptr, std::memory_order_release); return -1; } }