Changeset View
Changeset View
Standalone View
Standalone View
src/kcrash.cpp
Show First 20 Lines • Show All 108 Lines • ▼ Show 20 Line(s) | |||||
109 | { | 109 | { | ||
110 | KCrash::initialize(); | 110 | KCrash::initialize(); | ||
111 | } | 111 | } | ||
112 | Q_COREAPP_STARTUP_FUNCTION(kcrashInitialize) | 112 | Q_COREAPP_STARTUP_FUNCTION(kcrashInitialize) | ||
113 | 113 | | |||
114 | namespace KCrash | 114 | namespace KCrash | ||
115 | { | 115 | { | ||
116 | void setApplicationFilePath(const QString &filePath); | 116 | void setApplicationFilePath(const QString &filePath); | ||
117 | void startProcess(int argc, const char *argv[], bool waitAndExit); | 117 | void startProcess(int argc, const char *argv[], bool waitAndExit, bool *started=nullptr); | ||
118 | 118 | | |||
119 | #if defined(Q_OS_WIN) | 119 | #if defined(Q_OS_WIN) | ||
120 | LONG WINAPI win32UnhandledExceptionFilter(_EXCEPTION_POINTERS *exceptionInfo); | 120 | LONG WINAPI win32UnhandledExceptionFilter(_EXCEPTION_POINTERS *exceptionInfo); | ||
121 | #endif | 121 | #endif | ||
122 | } | 122 | } | ||
123 | 123 | | |||
124 | void KCrash::initialize() | 124 | void KCrash::initialize() | ||
125 | { | 125 | { | ||
▲ Show 20 Lines • Show All 246 Lines • ▼ Show 20 Line(s) | |||||
372 | 372 | | |||
373 | void | 373 | void | ||
374 | KCrash::defaultCrashHandler(int sig) | 374 | KCrash::defaultCrashHandler(int sig) | ||
375 | { | 375 | { | ||
376 | // WABA: Do NOT use qDebug() in this function because it is much too risky! | 376 | // WABA: Do NOT use qDebug() in this function because it is much too risky! | ||
377 | // Handle possible recursions | 377 | // Handle possible recursions | ||
378 | static int crashRecursionCounter = 0; | 378 | static int crashRecursionCounter = 0; | ||
379 | crashRecursionCounter++; // Nothing before this, please ! | 379 | crashRecursionCounter++; // Nothing before this, please ! | ||
380 | bool drKonqiDidStart = false; | ||||
380 | 381 | | |||
381 | #if !defined(Q_OS_WIN) | 382 | #if !defined(Q_OS_WIN) | ||
382 | signal(SIGALRM, SIG_DFL); | 383 | signal(SIGALRM, SIG_DFL); | ||
383 | alarm(3); // Kill me... (in case we deadlock in malloc) | 384 | alarm(3); // Kill me... (in case we deadlock in malloc) | ||
384 | #endif | 385 | #endif | ||
385 | 386 | | |||
386 | #ifdef Q_OS_SOLARIS | 387 | #ifdef Q_OS_SOLARIS | ||
387 | (void) printstack(2 /* stderr, assuming it's still open. */); | 388 | (void) printstack(2 /* stderr, assuming it's still open. */); | ||
▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Line(s) | 519 | #if defined(Q_OS_WIN) | |||
520 | sprintf(threadId, "%d", GetCurrentThreadId()); | 521 | sprintf(threadId, "%d", GetCurrentThreadId()); | ||
521 | argv[i++] = "--thread"; | 522 | argv[i++] = "--thread"; | ||
522 | argv[i++] = threadId; | 523 | argv[i++] = threadId; | ||
523 | #endif | 524 | #endif | ||
524 | 525 | | |||
525 | // NULL terminated list | 526 | // NULL terminated list | ||
526 | argv[i] = nullptr; | 527 | argv[i] = nullptr; | ||
527 | 528 | | |||
528 | startProcess(i, argv, true); | 529 | startProcess(i, argv, true, &drKonqiDidStart); | ||
529 | } | 530 | } | ||
530 | 531 | | |||
532 | if (!drKonqiDidStart) { | ||||
531 | if (crashRecursionCounter < 4) { | 533 | if (crashRecursionCounter < 4) { | ||
532 | fprintf(stderr, "Unable to start Dr. Konqi\n"); | 534 | fprintf(stderr, "Unable to start Dr. Konqi\n"); | ||
533 | } | 535 | } | ||
534 | 536 | | |||
537 | // re-raise the signal but only if DrKonqi wasn't cancelled | ||||
535 | if (s_coreConfig->isProcess()) { | 538 | if (s_coreConfig->isProcess()) { | ||
536 | fprintf(stderr, "Re-raising signal for core dump handling.\n"); | 539 | fprintf(stderr, "Re-raising signal for core dump handling.\n"); | ||
537 | KCrash::setCrashHandler(nullptr); | 540 | KCrash::setCrashHandler(nullptr); | ||
538 | raise(sig); | 541 | raise(sig); | ||
539 | // not getting here | 542 | // not getting here | ||
540 | } | 543 | } | ||
544 | } | ||||
541 | 545 | | |||
542 | _exit(255); | 546 | _exit(255); | ||
543 | } | 547 | } | ||
544 | 548 | | |||
545 | #if defined(Q_OS_WIN) | 549 | #if defined(Q_OS_WIN) | ||
546 | 550 | | |||
547 | void KCrash::startProcess(int argc, const char *argv[], bool waitAndExit) | 551 | void KCrash::startProcess(int argc, const char *argv[], bool waitAndExit, bool *started) | ||
548 | { | 552 | { | ||
549 | QString cmdLine; | 553 | QString cmdLine; | ||
550 | for (int i = 0; i < argc; ++i) { | 554 | for (int i = 0; i < argc; ++i) { | ||
551 | cmdLine.append(QLatin1Char('\"')); | 555 | cmdLine.append(QLatin1Char('\"')); | ||
552 | cmdLine.append(QFile::decodeName(argv[i])); | 556 | cmdLine.append(QFile::decodeName(argv[i])); | ||
553 | cmdLine.append(QStringLiteral("\" ")); | 557 | cmdLine.append(QStringLiteral("\" ")); | ||
554 | } | 558 | } | ||
555 | 559 | | |||
556 | PROCESS_INFORMATION procInfo; | 560 | PROCESS_INFORMATION procInfo; | ||
557 | STARTUPINFOW startupInfo = { sizeof(STARTUPINFO), 0, 0, 0, | 561 | STARTUPINFOW startupInfo = { sizeof(STARTUPINFO), 0, 0, 0, | ||
558 | (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, | 562 | (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, | ||
559 | (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, | 563 | (ulong)CW_USEDEFAULT, (ulong)CW_USEDEFAULT, | ||
560 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 564 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
561 | }; | 565 | }; | ||
562 | 566 | | |||
563 | bool success = CreateProcess(0, (wchar_t *) cmdLine.utf16(), NULL, NULL, | 567 | bool success = CreateProcess(0, (wchar_t *) cmdLine.utf16(), NULL, NULL, | ||
564 | false, CREATE_UNICODE_ENVIRONMENT, NULL, NULL, | 568 | false, CREATE_UNICODE_ENVIRONMENT, NULL, NULL, | ||
565 | &startupInfo, &procInfo); | 569 | &startupInfo, &procInfo); | ||
566 | 570 | | |||
571 | if (started) { | ||||
572 | *started = success; | ||||
573 | } | ||||
574 | | ||||
567 | if (success && waitAndExit) { | 575 | if (success && waitAndExit) { | ||
568 | // wait for child to exit | 576 | // wait for child to exit | ||
569 | WaitForSingleObject(procInfo.hProcess, INFINITE); | 577 | WaitForSingleObject(procInfo.hProcess, INFINITE); | ||
570 | _exit(253); | 578 | _exit(253); | ||
571 | } | 579 | } | ||
572 | } | 580 | } | ||
573 | 581 | | |||
574 | //glue function for calling the unix signal handler from the windows unhandled exception filter | 582 | //glue function for calling the unix signal handler from the windows unhandled exception filter | ||
Show All 25 Lines | 607 | if (s_crashHandler) { | |||
600 | s_crashHandler(exceptionInfo->ExceptionRecord->ExceptionCode); | 608 | s_crashHandler(exceptionInfo->ExceptionRecord->ExceptionCode); | ||
601 | } | 609 | } | ||
602 | 610 | | |||
603 | CloseHandle(hMapFile); | 611 | CloseHandle(hMapFile); | ||
604 | return EXCEPTION_EXECUTE_HANDLER; //allow windows to do the default action (terminate) | 612 | return EXCEPTION_EXECUTE_HANDLER; //allow windows to do the default action (terminate) | ||
605 | } | 613 | } | ||
606 | #else | 614 | #else | ||
607 | 615 | | |||
608 | static bool startProcessInternal(int argc, const char *argv[], bool waitAndExit, bool directly); | 616 | static bool startProcessInternal(int argc, const char *argv[], bool waitAndExit, bool directly, bool *started=nullptr); | ||
609 | static pid_t startFromKdeinit(int argc, const char *argv[]); | 617 | static pid_t startFromKdeinit(int argc, const char *argv[]); | ||
610 | static pid_t startDirectly(const char *argv[]); | 618 | static pid_t startDirectly(const char *argv[]); | ||
611 | static int write_socket(int sock, char *buffer, int len); | 619 | static int write_socket(int sock, char *buffer, int len); | ||
612 | static int read_socket(int sock, char *buffer, int len); | 620 | static int read_socket(int sock, char *buffer, int len); | ||
613 | static int openSocket(); | 621 | static int openSocket(); | ||
614 | 622 | | |||
615 | void KCrash::startProcess(int argc, const char *argv[], bool waitAndExit) | 623 | void KCrash::startProcess(int argc, const char *argv[], bool waitAndExit, bool *started) | ||
616 | { | 624 | { | ||
617 | bool startDirectly = true; | 625 | bool startDirectly = true; | ||
618 | 626 | | |||
619 | #ifndef Q_OS_OSX | 627 | #ifndef Q_OS_OSX | ||
620 | // First try to start the app via kdeinit, if the AlwaysDirectly flag hasn't been specified. | 628 | // First try to start the app via kdeinit, if the AlwaysDirectly flag hasn't been specified. | ||
621 | // This is done because it is dangerous to use fork() in the crash handler | 629 | // This is done because it is dangerous to use fork() in the crash handler | ||
622 | // (there can be functions registered to be performed before fork(), for example handling | 630 | // (there can be functions registered to be performed before fork(), for example handling | ||
623 | // of malloc locking, which doesn't work when malloc crashes because of heap corruption). | 631 | // of malloc locking, which doesn't work when malloc crashes because of heap corruption). | ||
624 | if (!(s_flags & AlwaysDirectly)) { | 632 | if (!(s_flags & AlwaysDirectly)) { | ||
625 | startDirectly = !startProcessInternal(argc, argv, waitAndExit, false); | 633 | startDirectly = !startProcessInternal(argc, argv, waitAndExit, false, started); | ||
626 | } | 634 | } | ||
627 | #endif | 635 | #endif | ||
628 | 636 | | |||
629 | // If we can't reach kdeinit, we can still at least try to fork() | 637 | // If we can't reach kdeinit, we can still at least try to fork() | ||
630 | if (startDirectly) { | 638 | if (startDirectly) { | ||
631 | startProcessInternal(argc, argv, waitAndExit, true); | 639 | startProcessInternal(argc, argv, waitAndExit, true, started); | ||
632 | } | 640 | } | ||
633 | } | 641 | } | ||
634 | 642 | | |||
635 | static bool startProcessInternal(int argc, const char *argv[], bool waitAndExit, bool directly) | 643 | static bool startProcessInternal(int argc, const char *argv[], bool waitAndExit, bool directly, bool *started) | ||
636 | { | 644 | { | ||
637 | fprintf(stderr, "KCrash: Attempting to start %s %s\n", argv[0], directly ? "directly" : "from kdeinit"); | 645 | fprintf(stderr, "KCrash: Attempting to start %s %s\n", argv[0], directly ? "directly" : "from kdeinit"); | ||
638 | 646 | | |||
639 | pid_t pid = directly ? startDirectly(argv) : startFromKdeinit(argc, argv); | 647 | pid_t pid = directly ? startDirectly(argv) : startFromKdeinit(argc, argv); | ||
640 | 648 | | |||
649 | if (started) { | ||||
650 | *started = pid > 0; | ||||
651 | } | ||||
652 | | ||||
641 | if (pid > 0 && waitAndExit) { | 653 | if (pid > 0 && waitAndExit) { | ||
642 | // Seems we made it.... | 654 | // Seems we made it.... | ||
643 | alarm(0); //stop the pending alarm that was set at the top of the defaultCrashHandler | 655 | alarm(0); //stop the pending alarm that was set at the top of the defaultCrashHandler | ||
644 | 656 | | |||
645 | // Wait forever until the started process exits. This code path is executed | 657 | // Wait forever until the started process exits. This code path is executed | ||
646 | // when launching drkonqi. Note that drkonqi will stop this process in the meantime. | 658 | // when launching drkonqi. Note that drkonqi will stop this process in the meantime. | ||
647 | if (directly) { | 659 | if (directly) { | ||
648 | //if the process was started directly, use waitpid(), as it's a child... | 660 | //if the process was started directly, use waitpid(), as it's a child... | ||
▲ Show 20 Lines • Show All 183 Lines • Show Last 20 Lines |