1
0
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:
Martin Prikryl
2026-10-09 17:04:00 +00:00
parent 4fc182de35
commit aaae9dcb51
5 changed files with 108 additions and 26 deletions

View File

@@ -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;
}
//---------------------------------------------------------------------------

View File

@@ -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);

View File

@@ -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);

View File

@@ -61,6 +61,7 @@ private:
void AccessViolationTest();
void __fastcall LookupAddress();
void InternalExceptionTest();
void AbnormalTerminationTest();
void __fastcall DoLoadThirdParty();
void __fastcall ShiftControls(int From, int Diff);

View File

@@ -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()
{