mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Allowing to report abnormal program terminations + Handling all types of exceptions
Source commit: 469bb8038a53cf2510d92222e66351ba3c6c4a66
This commit is contained in:
@@ -9,12 +9,31 @@ USEFORM("forms\ScpExplorer.cpp", ScpExplorerForm);
|
||||
//---------------------------------------------------------------------------
|
||||
#include <ProgParams.h>
|
||||
#include <PuttyTools.h>
|
||||
#include <signal.h>
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall AppLogImpl(UnicodeString S)
|
||||
{
|
||||
AppLog(S);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
NORETURN void TerminateHandler()
|
||||
{
|
||||
AppLog(L"Terminate handler");
|
||||
abort();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void AbortSignalHandler(int Signal)
|
||||
{
|
||||
AppLogFmt(L"Abort signal handler [%d]", (Signal));
|
||||
UnicodeString Message = MainInstructions(L"Abnormal program termination");
|
||||
std::unique_ptr<TStrings> MoreMessages(new TStringList());
|
||||
UnicodeString ReportErrorText = Trim(FMTLOAD(REPORT_ERROR, (EmptyStr)));
|
||||
MoreMessages->Add(ReportErrorText);
|
||||
std::unique_ptr<TStrings> StackTrace(GetCurrentStackTrace());
|
||||
AppendStackTrace(MoreMessages.get(), StackTrace.get());
|
||||
MoreMessageDialog(Message, MoreMessages.get(), qtError, qaOK | qaReport, EmptyStr);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
int WINAPI wWinMain(HINSTANCE, HINSTANCE, wchar_t *, int)
|
||||
{
|
||||
int Result = 0;
|
||||
@@ -59,6 +78,9 @@ int WINAPI wWinMain(HINSTANCE, HINSTANCE, wchar_t *, int)
|
||||
InitializeSystemSettings();
|
||||
AddStartupSequence(L"S");
|
||||
|
||||
std::set_terminate(TerminateHandler);
|
||||
signal(SIGABRT, AbortSignalHandler);
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
@@ -97,6 +119,17 @@ int WINAPI wWinMain(HINSTANCE, HINSTANCE, wchar_t *, int)
|
||||
{
|
||||
ShowExtendedException(&E);
|
||||
}
|
||||
catch (std::exception &E)
|
||||
{
|
||||
UnicodeString Message = E.what();
|
||||
Message = FORMAT(L"%s (std::exception)", (Message));
|
||||
Application->MessageBox(Message.c_str(), L"Fatal Error", MB_OK | MB_ICONERROR);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
UnicodeString Message = L"Unknown exception";
|
||||
MoreMessageDialog(Message, nullptr, qtError, qaOK, EmptyStr);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -39,7 +39,9 @@ class TOptions;
|
||||
TOptions * __fastcall GetGlobalOptions();
|
||||
|
||||
void __fastcall ShowExtendedException(Exception * E);
|
||||
void AppendStackTrace(TStrings * MoreMessages, TStrings * StackTrace);
|
||||
bool AppendExceptionStackTrace(Exception * E, TStrings *& MoreMessages);
|
||||
TStrings * GetCurrentStackTrace();
|
||||
void __fastcall IgnoreException(const std::type_info & ExceptionType);
|
||||
UnicodeString GetExceptionDebugInfo(Exception * E);
|
||||
|
||||
|
||||
@@ -355,7 +355,11 @@ void __fastcall TAboutDialog::OKButtonMouseDown(TObject * /*Sender*/,
|
||||
{
|
||||
if (Button == mbRight)
|
||||
{
|
||||
if (Shift.Contains(ssAlt))
|
||||
if (Shift.Contains(ssAlt) && Shift.Contains(ssShift))
|
||||
{
|
||||
AbnormalTerminationTest();
|
||||
}
|
||||
else if (Shift.Contains(ssAlt))
|
||||
{
|
||||
AccessViolationTest();
|
||||
}
|
||||
@@ -450,6 +454,14 @@ void TAboutDialog::InternalExceptionTest()
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TAboutDialog::AbnormalTerminationTest()
|
||||
{
|
||||
std::unique_ptr<TStringList> Releaser(new TStringList());
|
||||
delete Releaser.get();
|
||||
// for some reason two delete's won't do (that crashes somehow), although reset does delete internally too anyway
|
||||
Releaser.reset(nullptr);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TAboutDialog::ExpatLicenceHandler(TObject * /*Sender*/)
|
||||
{
|
||||
DoLicenseDialog(lcExpat);
|
||||
|
||||
@@ -61,6 +61,7 @@ private:
|
||||
void AccessViolationTest();
|
||||
void __fastcall LookupAddress();
|
||||
void InternalExceptionTest();
|
||||
void AbnormalTerminationTest();
|
||||
void __fastcall DoLoadThirdParty();
|
||||
void __fastcall ShiftControls(int From, int Diff);
|
||||
|
||||
|
||||
@@ -634,6 +634,21 @@ static TStrings * GetExceptionStackTraceStrings(Exception * E)
|
||||
return StackTrace.release();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString GetFrameSymbol(const UnicodeString & Frame)
|
||||
{
|
||||
UnicodeString Result;
|
||||
// The last line might be empty
|
||||
if (!Frame.IsEmpty())
|
||||
{
|
||||
int P = Frame.Pos(L")");
|
||||
if (DebugAlwaysTrue(P > 0))
|
||||
{
|
||||
Result = Frame.SubString(P + 1, Frame.Length() - P).Trim();
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString GetExceptionDebugInfo(Exception * E)
|
||||
{
|
||||
UnicodeString Result;
|
||||
@@ -643,31 +658,33 @@ UnicodeString GetExceptionDebugInfo(Exception * E)
|
||||
for (int Index = 0; Index < StackTrace->Count; Index++)
|
||||
{
|
||||
UnicodeString Frame = StackTrace->Strings[Index];
|
||||
// The last line might be empty
|
||||
if (!Frame.IsEmpty())
|
||||
UnicodeString Symbol = GetFrameSymbol(Frame);
|
||||
if (!Symbol.IsEmpty() &&
|
||||
(Symbol != L"KERNELBASE.dll.RaiseException") &&
|
||||
(Symbol != L"Jclhookexcept::JclAddExceptNotifier") &&
|
||||
(Symbol != L"_ReThrowException") &&
|
||||
(Symbol != L"____ExceptionHandler") &&
|
||||
(Symbol != L"__ExceptionHandler") &&
|
||||
(Symbol != L"___doGlobalUnwind") &&
|
||||
(Symbol != L"_ThrowExceptionLDTC"))
|
||||
{
|
||||
int P = Frame.Pos(L")");
|
||||
if (DebugAlwaysTrue(P > 0))
|
||||
{
|
||||
UnicodeString Symbol = Frame.SubString(P + 1, Frame.Length() - P).Trim();
|
||||
|
||||
if ((Symbol != L"KERNELBASE.dll.RaiseException") &&
|
||||
(Symbol != L"Jclhookexcept::JclAddExceptNotifier") &&
|
||||
(Symbol != L"_ReThrowException") &&
|
||||
(Symbol != L"____ExceptionHandler") &&
|
||||
(Symbol != L"__ExceptionHandler") &&
|
||||
(Symbol != L"___doGlobalUnwind") &&
|
||||
(Symbol != L"_ThrowExceptionLDTC"))
|
||||
{
|
||||
AddToList(Result, Symbol, L";");
|
||||
}
|
||||
}
|
||||
AddToList(Result, Symbol, L";");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void AppendStackTrace(TStrings * MoreMessages, TStrings * StackTrace)
|
||||
{
|
||||
if (!MoreMessages->Text.IsEmpty())
|
||||
{
|
||||
MoreMessages->Text = MoreMessages->Text + "\n";
|
||||
}
|
||||
MoreMessages->Text = MoreMessages->Text + LoadStr(STACK_TRACE) + "\n";
|
||||
MoreMessages->AddStrings(StackTrace);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool AppendExceptionStackTrace(Exception * E, TStrings *& MoreMessages)
|
||||
{
|
||||
bool Result = false;
|
||||
@@ -683,12 +700,7 @@ bool AppendExceptionStackTrace(Exception * E, TStrings *& MoreMessages)
|
||||
MoreMessages = OwnedMoreMessages.get();
|
||||
Result = true;
|
||||
}
|
||||
if (!MoreMessages->Text.IsEmpty())
|
||||
{
|
||||
MoreMessages->Text = MoreMessages->Text + "\n";
|
||||
}
|
||||
MoreMessages->Text = MoreMessages->Text + LoadStr(STACK_TRACE) + "\n";
|
||||
MoreMessages->AddStrings(StackTrace.get());
|
||||
AppendStackTrace(MoreMessages, StackTrace.get());
|
||||
|
||||
OwnedMoreMessages.release();
|
||||
}
|
||||
@@ -750,6 +762,28 @@ unsigned int __fastcall FatalExceptionMessageDialog(
|
||||
return ExceptionMessageDialog(E, Type, MessageFormat, Answers, HelpKeyword, &AParams);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TStrings * GetCurrentStackTrace()
|
||||
{
|
||||
std::unique_ptr<TJclStackInfoList> StackInfoList(JclCreateStackList(false, 0, Caller(0, false)));
|
||||
std::unique_ptr<TStrings> Result(StackInfoListToStrings(StackInfoList.get()));
|
||||
for (int Index = 0; Index < Result->Count; Index++)
|
||||
{
|
||||
UnicodeString Frame = Result->Strings[Index];
|
||||
UnicodeString Symbol = GetFrameSymbol(Frame);
|
||||
if ((Symbol == L"GetCurrentStackTrace") ||
|
||||
(Symbol == L"Jcldebug::JclCreateStackList") ||
|
||||
(Symbol == L"AbortSignalHandler") ||
|
||||
(Symbol == L"_raise") ||
|
||||
(Symbol == L"std::terminate") ||
|
||||
(Symbol == L"___cpp_terminate"))
|
||||
{
|
||||
Result->Delete(Index);
|
||||
Index--;
|
||||
}
|
||||
}
|
||||
return Result.release();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------
|
||||
void * __fastcall BusyStart()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user