From 05e3582c126663120b82a2eec8fd12dcb6929064 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 27 Mar 2020 04:30:09 +0100 Subject: [PATCH] Port to 3.1 - Fix handling thread abort in HelperMethodFrame (#28029) The thread abort during func eval from a managed debugger on Linux and macOS was sometimes causing the debuggee to exit with unhandled c++ PAL_SEHException. The reason is that the thread abort detection that is done in the HELPER_METHOD_FRAME_BEGIN and ...END macros was done outside of the INSTALL_MANAGED_EXCEPTION_DISPATCHER / UNINSTALL_MANAGED_EXCEPTION_DISPATCHER region and so the exception thrown when thread abort request is detected there was not being caught and translated into a call to DispatchManagedException. Since the caller frame was a managed function frame, the C++ exception handling didn't know how to unwind it and so it declared the exception being unhandled. This fix moves the check for the thread abort out of the HelperMethodFrame::Push/Pop into a new method and calls that explicitly from the HELPER_METHOD_* macros inside the INSTALL_MANAGED_EXCEPTION_DISPATCHER / UNINSTALL_MANAGED_EXCEPTION_DISPATCHER region. That way, the thread abort exception is properly handled. # Customer impact .NET Core apps randomly terminate with unhandled c++ PAL_SEHException when a customer debugs an app under managed debuggers (VS Code, 3rd party debuggers) and tries to view a property value. # Regression? No, this problem has been present since .NET Core 1.0 # Testing CoreCLR pri 1 tests and .NET Core debugger tests. # Risk --- src/vm/fcall.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/vm/fcall.h b/src/vm/fcall.h index 7569c850cc60..f15d22a166fa 100644 --- a/src/vm/fcall.h +++ b/src/vm/fcall.h @@ -567,19 +567,21 @@ LPVOID __FCThrowArgument(LPVOID me, enum RuntimeExceptionKind reKind, LPCWSTR ar FORLAZYMACHSTATE_DEBUG_OK_TO_RETURN_END; \ INDEBUG(__helperframe.SetAddrOfHaveCheckedRestoreState(&__haveCheckedRestoreState)); \ DEBUG_ASSURE_NO_RETURN_BEGIN(HELPER_METHOD_FRAME); \ - INCONTRACT(FCallGCCanTrigger::Enter()); \ - __helperframe.Push(); \ - MAKE_CURRENT_THREAD_AVAILABLE_EX(__helperframe.GetThread()); \ + INCONTRACT(FCallGCCanTrigger::Enter()); #define HELPER_METHOD_FRAME_BEGIN_EX(ret, helperFrame, gcpoll, allowGC) \ HELPER_METHOD_FRAME_BEGIN_EX_BODY(ret, helperFrame, gcpoll, allowGC) \ /* TODO TURN THIS ON!!! */ \ /* gcpoll; */ \ INSTALL_MANAGED_EXCEPTION_DISPATCHER; \ + __helperframe.Push(); \ + MAKE_CURRENT_THREAD_AVAILABLE_EX(__helperframe.GetThread()); \ INSTALL_UNWIND_AND_CONTINUE_HANDLER_FOR_HMF(&__helperframe); #define HELPER_METHOD_FRAME_BEGIN_EX_NOTHROW(ret, helperFrame, gcpoll, allowGC, probeFailExpr) \ HELPER_METHOD_FRAME_BEGIN_EX_BODY(ret, helperFrame, gcpoll, allowGC) \ + __helperframe.Push(); \ + MAKE_CURRENT_THREAD_AVAILABLE_EX(__helperframe.GetThread()); \ /* TODO TURN THIS ON!!! */ \ /* gcpoll; */ @@ -596,7 +598,6 @@ LPVOID __FCThrowArgument(LPVOID me, enum RuntimeExceptionKind reKind, LPCWSTR ar #define HELPER_METHOD_FRAME_END_EX_BODY(gcpoll,allowGC) \ /* TODO TURN THIS ON!!! */ \ /* gcpoll; */ \ - __helperframe.Pop(); \ DEBUG_ASSURE_NO_RETURN_END(HELPER_METHOD_FRAME); \ INCONTRACT(FCallGCCanTrigger::Leave(__FUNCTION__, __FILE__, __LINE__)); \ FORLAZYMACHSTATE(alwaysZero = \ @@ -607,10 +608,12 @@ LPVOID __FCThrowArgument(LPVOID me, enum RuntimeExceptionKind reKind, LPCWSTR ar #define HELPER_METHOD_FRAME_END_EX(gcpoll,allowGC) \ UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; \ + __helperframe.Pop(); \ UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; \ HELPER_METHOD_FRAME_END_EX_BODY(gcpoll,allowGC); #define HELPER_METHOD_FRAME_END_EX_NOTHROW(gcpoll,allowGC) \ + __helperframe.Pop(); \ HELPER_METHOD_FRAME_END_EX_BODY(gcpoll,allowGC); #define HELPER_METHOD_FRAME_BEGIN_ATTRIB(attribs) \