From 5fb8519c281f207e769605ea07673e8d5cb8be19 Mon Sep 17 00:00:00 2001 From: Alex Alabuzhev Date: Wed, 24 Aug 2016 15:13:23 +0000 Subject: [PATCH] exceptions handling, fix for 'mode x, y' --- far/changelog | 6 ++ far/execute.cpp | 7 ++- far/farexcpt.cpp | 128 ++++++++++++++++++++++++++++------------ far/farexcpt.hpp | 2 +- far/findfile.cpp | 37 ++++++++---- far/findfile.hpp | 5 ++ far/initguid.cpp | 1 - far/main.cpp | 24 -------- far/makefile_gcc_common | 1 + far/plclass.hpp | 13 ++-- 10 files changed, 144 insertions(+), 80 deletions(-) diff --git a/far/changelog b/far/changelog index 6a984ff6c9..b5899ea770 100644 --- a/far/changelog +++ b/far/changelog @@ -1,3 +1,9 @@ +drkns 24.08.2016 18:08:24 +0200 - build 4766 + +1. Уточнения обработки исключений. + +2. После 4709 не работало изменение размера консоли с помощью "mode x, y". + drkns 23.08.2016 11:20:47 +0200 - build 4765 1. Не работал поиск в UTF8-файлах во вьювере. diff --git a/far/execute.cpp b/far/execute.cpp index 4b5e5b6243..91372900e3 100644 --- a/far/execute.cpp +++ b/far/execute.cpp @@ -1064,9 +1064,12 @@ void Execute(execute_info& Info, bool FolderRun, bool Silent, const std::functio CONSOLE_CURSOR_INFO cci = { CursorSize, Visible }; Console().SetCursorInfo(cci); - if (IsConsoleSizeChanged()) { - ChangeVideoMode(ScrY, ScrX); + COORD ConSize; + if (Console().GetSize(ConSize) && (ConSize.X != ScrX + 1 || ConSize.Y != ScrY + 1)) + { + ChangeVideoMode(ConSize.Y, ConSize.X); + } } if (Global->Opt->Exec.RestoreCPAfterExecute) diff --git a/far/farexcpt.cpp b/far/farexcpt.cpp index 8b7456b528..399197c35c 100644 --- a/far/farexcpt.cpp +++ b/far/farexcpt.cpp @@ -519,24 +519,39 @@ void RestoreGPFaultUI() SetErrorMode(Global->ErrorMode&~SEM_NOGPFAULTERRORBOX); } -bool ProcessSEHException(EXCEPTION_POINTERS *xp, const wchar_t* Function, Plugin *PluginModule) -{ - return ProcessGenericException(xp, Function, PluginModule, nullptr); -} - bool ProcessStdException(const std::exception& e, const wchar_t* Function, Plugin* Module) { - EXCEPTION_RECORD ExceptionRecord {}; - CONTEXT ContextRecord {}; + EXCEPTION_RECORD ExceptionRecord{}; + CONTEXT ContextRecord{}; EXCEPTION_POINTERS xp = { &ExceptionRecord, &ContextRecord }; - if (!tracer::get_exception_context(&e, ExceptionRecord, ContextRecord)) + + EXCEPTION_POINTERS* XpPtr; + + if (const auto se = dynamic_cast(&e)) { - // std::exception to EXCEPTION_POINTERS translation relies on Microsoft C++ exception implementation. - // It won't work in gcc etc. - // Set ExceptionCode manually so ProcessGenericException will at least report it as std::exception and display what() - xp.ExceptionRecord->ExceptionCode = EXCEPTION_MICROSOFT_CPLUSPLUS; + XpPtr = se->GetInfo(); } - return ProcessGenericException(&xp, Function, Module, e.what()); + else + { + if (!tracer::get_exception_context(&e, ExceptionRecord, ContextRecord)) + { + // std::exception to EXCEPTION_POINTERS translation relies on Microsoft C++ exception implementation. + // It won't work in gcc etc. + // Set ExceptionCode manually so ProcessGenericException will at least report it as std::exception and display what() + xp.ExceptionRecord->ExceptionCode = EXCEPTION_MICROSOFT_CPLUSPLUS; + } + XpPtr = &xp; + } + return ProcessGenericException(XpPtr, Function, Module, e.what()); +} + +bool ProcessUnknownException(const wchar_t* Function, Plugin* Module) +{ + EXCEPTION_RECORD ExceptionRecord{}; + CONTEXT ContextRecord{}; + EXCEPTION_POINTERS xp = { &ExceptionRecord, &ContextRecord }; + + return ProcessGenericException(&xp, Function, Module, nullptr); } LONG WINAPI FarUnhandledExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo) @@ -550,22 +565,22 @@ LONG WINAPI FarUnhandledExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo) } -static DWORD WINAPI ProcessSEHExceptionWrapper(EXCEPTION_POINTERS* xp) +static DWORD WINAPI ProcessGenericExceptionWrapper(EXCEPTION_POINTERS* xp) { - ProcessSEHException(xp, nullptr); + ProcessGenericException(xp, nullptr, nullptr, nullptr); return 0; } LONG WINAPI VectoredExceptionHandler(EXCEPTION_POINTERS *xp) { - // restore stack & call ProcessSEHExceptionWrapper + // restore stack & call ProcessGenericExceptionWrapper if (xp->ExceptionRecord->ExceptionCode == (DWORD)STATUS_STACK_OVERFLOW) { #if 1 // it is much better way than hack stack and modify original context //#ifdef _M_IA64 // TODO: Bad way to restore IA64 stacks (CreateThread) // Can you do smartly? See REMINDER file, section IA64Stacks - static HANDLE hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)ProcessSEHExceptionWrapper, xp, 0, nullptr); + static HANDLE hThread = CreateThread(nullptr, 0, reinterpret_cast(ProcessGenericExceptionWrapper), xp, 0, nullptr); if (hThread) { WaitForSingleObject(hThread, INFINITE); @@ -587,14 +602,14 @@ LONG WINAPI VectoredExceptionHandler(EXCEPTION_POINTERS *xp) //stack.args[2] = ... //stack.args[3] = ... xp->ContextRecord->Esp = reinterpret_cast(&stack.ret_addr); - xp->ContextRecord->Eip = reinterpret_cast(&ProcessSEHExceptionWrapper); + xp->ContextRecord->Eip = reinterpret_cast(&ProcessGenericExceptionWrapper); #else xp->ContextRecord->Rcx = reinterpret_cast(xp); //xp->ContextRecord->Rdx = ... //xp->ContextRecord->R8 = ... //xp->ContextRecord->R9 = ... xp->ContextRecord->Rsp = reinterpret_cast(&stack.ret_addr); - xp->ContextRecord->Rip = reinterpret_cast(&ProcessSEHExceptionWrapper); + xp->ContextRecord->Rip = reinterpret_cast(&ProcessGenericExceptionWrapper); #endif return EXCEPTION_CONTINUE_EXECUTION; #endif @@ -646,9 +661,28 @@ static int ExceptionTestHook(Manager::Key key) key() == KEY_RCTRLALTAPPS ) { + enum class exception_types + { + cpp_std, + cpp_unknown, + access_violation_read, + access_violation_write, + divide_by_zero, + illegal_instruction, + stack_overflow, + fp_divide_by_zero, + breakpoint, +#ifdef _M_IA64 + alignment_fault, +#endif + + count + }; + static const wchar_t* Names[] = { L"C++ std::exception", + L"C++ unknown exception", L"Access Violation (Read)", L"Access Violation (Write)", L"Divide by zero", @@ -677,6 +711,9 @@ static int ExceptionTestHook(Manager::Key key) L"EXCEPTION_INVALID_HANDLE", */ }; + + static_assert(std::size(Names) == static_cast(exception_types::count), "Incomplete Names array"); + static union { int i; @@ -694,23 +731,32 @@ static int ExceptionTestHook(Manager::Key key) }); int ExitCode = ModalMenu->Run(); + if (ExitCode == -1) + return TRUE; - switch (ExitCode) + switch (static_cast(ExitCode)) { - case -1: - return TRUE; - case 0: + case exception_types::cpp_std: throw MAKE_FAR_EXCEPTION("test error"); - case 1: + break; + + case exception_types::cpp_unknown: + throw 42; + break; + + case exception_types::access_violation_read: zero_const.i = *zero_const.iptr; break; - case 2: + + case exception_types::access_violation_write: *zero_const.iptr = 0; break; - case 3: + + case exception_types::divide_by_zero: zero_const.i = 1 / zero_const.i; break; - case 4: + + case exception_types::illegal_instruction: #if COMPILER == C_CL || COMPILER == C_INTEL #ifdef _M_IA64 const int REG_IA64_IntR0 = 1024; @@ -722,24 +768,32 @@ static int ExceptionTestHook(Manager::Key key) asm("ud2"); #endif break; - case 5: + + case exception_types::stack_overflow: Test_EXCEPTION_STACK_OVERFLOW(nullptr); break; - case 6: + + case exception_types::fp_divide_by_zero: zero_const.d = 1.0 / zero_const.d; break; - case 7: + + case exception_types::breakpoint: DebugBreak(); break; + #ifdef _M_IA64 - case 8: - { - BYTE temp[10] = {}; - double* val; - val = (double*)(&temp[3]); - printf("%lf\n", *val); - } + case exception_types::alignment_fault: + { + BYTE temp[10] = {}; + double* val; + val = (double*)(&temp[3]); + printf("%lf\n", *val); + break; + } #endif + case exception_types::count: + // makes no sense, just to make compiler happy + break; } Message(MSG_WARNING, 1, L"Test Exceptions failed", L"", Names[ExitCode], L"", MSG(MOk)); diff --git a/far/farexcpt.hpp b/far/farexcpt.hpp index ecd2406da9..984d7edccd 100644 --- a/far/farexcpt.hpp +++ b/far/farexcpt.hpp @@ -37,8 +37,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. class Plugin; -bool ProcessSEHException(EXCEPTION_POINTERS *xp, const wchar_t* Function, Plugin *Module = nullptr); bool ProcessStdException(const std::exception& e, const wchar_t* Function, Plugin* Module = nullptr); +bool ProcessUnknownException(const wchar_t* Function, Plugin* Module = nullptr); LONG WINAPI FarUnhandledExceptionFilter(EXCEPTION_POINTERS *ExceptionInfo); diff --git a/far/findfile.cpp b/far/findfile.cpp index 4231968cee..02704804ef 100644 --- a/far/findfile.cpp +++ b/far/findfile.cpp @@ -1373,6 +1373,17 @@ bool background_searcher::IsFileIncluded(PluginPanelItem* FileItem, const string intptr_t FindFiles::FindDlgProc(Dialog* Dlg, intptr_t Msg, intptr_t Param1, void* Param2) { SCOPED_ACTION(CriticalSectionLock)(PluginCS); + + if (!m_ExceptionPtr) + { + m_ExceptionPtr = m_Searcher->ExceptionPtr(); + if (m_ExceptionPtr) + { + Dlg->SendMessage(DM_CLOSE, 0, nullptr); + return TRUE; + } + } + auto& ListBox = Dlg->GetAllItem()[FD_LISTBOX].ListPtr; static bool Recurse=false; @@ -2628,16 +2639,9 @@ unsigned int background_searcher::ThreadRoutine(THREADPARAM* Param) Param->PluginMode? DoPreparePluginList(Param->Dlg, false) : DoPrepareFileList(Param->Dlg); ReleaseInFileSearch(); } - catch (const SException& e) + catch (...) { - if (ProcessSEHException(e.GetInfo(), L"FindFiles::ThreadRoutine")) - { - std::terminate(); - } - else - { - throw; - } + m_ExceptionPtr = std::current_exception(); } return 0; } @@ -2754,9 +2758,20 @@ bool FindFiles::FindFilesProcess() Thread FindThread(&Thread::join, &background_searcher::ThreadRoutine, &BC, &Param); Dlg->Process(); + + // BUGBUG + m_Searcher = nullptr; + + if (!m_ExceptionPtr) + { + m_ExceptionPtr = BC.ExceptionPtr(); + } + + if (m_ExceptionPtr) + { + std::rethrow_exception(m_ExceptionPtr); + } } - // BUGBUG - m_Searcher = nullptr; switch (Dlg->GetExitCode()) { diff --git a/far/findfile.hpp b/far/findfile.hpp index 42ccf78c05..2f933b24f8 100644 --- a/far/findfile.hpp +++ b/far/findfile.hpp @@ -124,6 +124,7 @@ class FindFiles: noncopyable time_check m_TimeCheck; // BUGBUG class background_searcher* m_Searcher; + std::exception_ptr m_ExceptionPtr; }; class background_searcher: noncopyable @@ -148,6 +149,8 @@ class background_searcher: noncopyable void Stop() const { StopEvent.Set(); } bool Stopped() const { return StopEvent.Signaled(); } + auto ExceptionPtr() const { return m_ExceptionPtr; } + private: void InitInFileSearch(); void ReleaseInFileSearch(); @@ -196,5 +199,7 @@ class background_searcher: noncopyable Event PauseEvent; Event StopEvent; + + std::exception_ptr m_ExceptionPtr; }; #endif // FINDFILE_HPP_8601893C_E4B7_4EC6_A79F_9C6E491FF5ED diff --git a/far/initguid.cpp b/far/initguid.cpp index f20996f30f..85dc8d4435 100644 --- a/far/initguid.cpp +++ b/far/initguid.cpp @@ -32,7 +32,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include "headers.hpp" #include "FarGuid.hpp" #include "DlgGuid.hpp" #include "KnownGuids.hpp" diff --git a/far/main.cpp b/far/main.cpp index 1ca9829383..8084c04557 100644 --- a/far/main.cpp +++ b/far/main.cpp @@ -766,18 +766,6 @@ static int mainImpl(const range& Args) { Result = MainProcess(strEditName, strViewName, DestNames[0], DestNames[1], StartLine, StartChar); } - catch (const SException& e) - { - if (ProcessSEHException(e.GetInfo(), L"mainImpl")) - { - std::terminate(); - } - else - { - RestoreGPFaultUI(); - throw; - } - } catch (const std::exception& e) { if (ProcessStdException(e, L"mainImpl")) @@ -819,18 +807,6 @@ int wmain(int Argc, wchar_t *Argv[]) static SCOPED_ACTION(os::com::co_initialize); return mainImpl(make_range(Argv + 1, Argv + Argc)); } - catch (const SException& e) - { - if (ProcessSEHException(e.GetInfo(), L"wmain")) - { - std::terminate(); - } - else - { - SetUnhandledExceptionFilter(nullptr); - throw; - } - } catch (const std::exception& e) { if (ProcessStdException(e, L"wmain")) diff --git a/far/makefile_gcc_common b/far/makefile_gcc_common index 082cca893a..601a7c16a5 100644 --- a/far/makefile_gcc_common +++ b/far/makefile_gcc_common @@ -76,6 +76,7 @@ CFLAGS += \ CCFLAGS = $(CFLAGS) -std=c++1z \ -Wnon-virtual-dtor \ -Woverloaded-virtual \ +-Wctor-dtor-privacy \ -Wzero-as-null-pointer-constant \ -Wsuggest-final-types \ -Wsuggest-final-methods \ diff --git a/far/plclass.hpp b/far/plclass.hpp index 3c68382a1b..839e95dc80 100644 --- a/far/plclass.hpp +++ b/far/plclass.hpp @@ -292,17 +292,22 @@ class Plugin: noncopyable Prologue(); ++Activity; SCOPE_EXIT{ --Activity; Epilogue(); }; + const auto ProcessException = [&](const auto& Handler, auto&&... ProcArgs) + { + Handler(ProcArgs..., m_Factory->ExportsNames()[T::export_id::value].UName, this)? HandleFailure(T::export_id::value) : throw; + }; + try { detail::ExecuteFunctionImpl(es, reinterpret_cast>(Exports[T::export_id::value].first), std::forward(Args)...); } - catch (const SException& e) + catch (const std::exception& e) { - ProcessSEHException(e.GetInfo(), m_Factory->ExportsNames()[T::export_id::value].UName, this)? HandleFailure(T::export_id::value) : throw; + ProcessException(ProcessStdException, e); } - catch (const std::exception& e) + catch (...) { - ProcessStdException(e, m_Factory->ExportsNames()[T::export_id::value].UName, this)? HandleFailure(T::export_id::value) : throw; + ProcessException(ProcessUnknownException); } }