Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,12 @@ class AsmOffsets
public const int SIZEOF__EHEnum = 0x20;
public const int OFFSETOF__StackFrameIterator__m_pRegDisplay = 0x20;
public const int OFFSETOF__ExInfo__m_pPrevExInfo = 0;
public const int OFFSETOF__ExInfo__m_pExContext = 0xa8;
public const int OFFSETOF__ExInfo__m_exception = 0xb0;
public const int OFFSETOF__ExInfo__m_kind = 0xb8;
public const int OFFSETOF__ExInfo__m_passNumber = 0xb9;
public const int OFFSETOF__ExInfo__m_idxCurClause = 0xbc;
public const int OFFSETOF__ExInfo__m_frameIter = 0xc0;
public const int OFFSETOF__ExInfo__m_pExContext = 0xa0;
public const int OFFSETOF__ExInfo__m_exception = 0xa8;
public const int OFFSETOF__ExInfo__m_kind = 0xb0;
public const int OFFSETOF__ExInfo__m_passNumber = 0xb1;
public const int OFFSETOF__ExInfo__m_idxCurClause = 0xb4;
public const int OFFSETOF__ExInfo__m_frameIter = 0xb8;
public const int OFFSETOF__ExInfo__m_notifyDebuggerSP = OFFSETOF__ExInfo__m_frameIter + SIZEOF__StackFrameIterator;
public const int OFFSETOF__ExInfo__m_pCatchHandler = OFFSETOF__ExInfo__m_frameIter + SIZEOF__StackFrameIterator + 0x48;
public const int OFFSETOF__ExInfo__m_handlingFrameSP = OFFSETOF__ExInfo__m_frameIter + SIZEOF__StackFrameIterator + 0x50;
Expand All @@ -217,12 +217,12 @@ class AsmOffsets
public const int SIZEOF__EHEnum = 0x10;
public const int OFFSETOF__StackFrameIterator__m_pRegDisplay = 0x14;
public const int OFFSETOF__ExInfo__m_pPrevExInfo = 0;
public const int OFFSETOF__ExInfo__m_pExContext = 0x5c;
public const int OFFSETOF__ExInfo__m_exception = 0x60;
public const int OFFSETOF__ExInfo__m_kind = 0x64;
public const int OFFSETOF__ExInfo__m_passNumber = 0x65;
public const int OFFSETOF__ExInfo__m_idxCurClause = 0x68;
public const int OFFSETOF__ExInfo__m_frameIter = 0x6c;
public const int OFFSETOF__ExInfo__m_pExContext = 0x58;
public const int OFFSETOF__ExInfo__m_exception = 0x5c;
public const int OFFSETOF__ExInfo__m_kind = 0x60;
public const int OFFSETOF__ExInfo__m_passNumber = 0x61;
public const int OFFSETOF__ExInfo__m_idxCurClause = 0x64;
public const int OFFSETOF__ExInfo__m_frameIter = 0x68;
public const int OFFSETOF__ExInfo__m_notifyDebuggerSP = OFFSETOF__ExInfo__m_frameIter + SIZEOF__StackFrameIterator;
public const int OFFSETOF__ExInfo__m_pCatchHandler = OFFSETOF__ExInfo__m_frameIter + SIZEOF__StackFrameIterator + 0x2c;
public const int OFFSETOF__ExInfo__m_handlingFrameSP = OFFSETOF__ExInfo__m_frameIter + SIZEOF__StackFrameIterator + 0x30;
Expand Down
12 changes: 7 additions & 5 deletions src/coreclr/debug/daccess/dacdbiimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4817,9 +4817,9 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::HasUnhandledException(VMPTR_Threa
else
{
// most managed exceptions are just a throwable bound to a
// native exception. In that case this handle will be non-null
OBJECTHANDLE ohException = pThread->GetThrowableAsHandle();
if (ohException != (OBJECTHANDLE)NULL)
// native exception. In that case the exception will be non-null
OBJECTREF exception = pThread->GetExceptionState()->GetThrowable();
if (exception != NULL)
{
// during the UEF we set the unhandled bit, if it is set the exception
// was unhandled
Expand Down Expand Up @@ -4955,8 +4955,10 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetCurrentException(VMPTR_Thread

Thread * pThread = vmThread.GetDacPtr();

// OBJECTHANDLEs are really just TADDRs.
OBJECTHANDLE ohException = pThread->GetThrowableAsHandle(); // ohException can be NULL
// Get the exception handle. The exception object is stored directly in ExInfo::m_exception,
// but debugger APIs require a handle. Use m_LastThrownObjectHandle which is kept in sync
// via SafeSetThrowables.
OBJECTHANDLE ohException = pThread->m_LastThrownObjectHandle;

if (ohException == (OBJECTHANDLE)NULL)
{
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3397,6 +3397,13 @@ class ClrDataExceptionState : public IXCLRDataExceptionState
Thread* thread,
ULONG32 flags,
ClrDataExStateType* exInfo,
// Target address of a slot containing the exception Object*.
// This may be a GC handle table slot (e.g. m_LastThrownObjectHandle)
// or the address of ExInfo::m_exception on the target stack.
// Both are valid: the ExInfo lives on the stack which is captured
// in dumps and stable while the target thread is suspended. The
// slot has the same lifetime as the ExInfo — both become invalid
// when ExInfo::PopExInfos calls ReleaseResources.
OBJECTHANDLE throwable,
ClrDataExStateType* prevExInfo);
virtual ~ClrDataExceptionState(void);
Expand Down
47 changes: 21 additions & 26 deletions src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3308,7 +3308,7 @@ ClrDataAccess::GetNestedExceptionData(CLRDATA_ADDRESS exception, CLRDATA_ADDRESS
}
else
{
*exceptionObject = TO_CDADDR(*PTR_TADDR(pExData->m_hThrowable));
*exceptionObject = dac_cast<TADDR>(pExData->m_exception);
*nextNestedException = PTR_HOST_TO_TADDR(pExData->m_pPrevNestedInfo);
}

Expand Down Expand Up @@ -4064,35 +4064,30 @@ HRESULT ClrDataAccess::GetClrWatsonBucketsWorker(Thread * pThread, GenericModeBl
// By default, there are no buckets
PTR_VOID pBuckets = NULL;

// Get the handle to the throwble
OBJECTHANDLE ohThrowable = pThread->GetThrowableAsHandle();
if (ohThrowable != NULL)
// Get the current throwable
OBJECTREF oThrowable = pThread->GetExceptionState()->GetThrowable();
if (oThrowable != NULL)
{
// Get the object from handle and check if the throwable is preallocated or not
OBJECTREF oThrowable = ObjectFromHandle(ohThrowable);
if (oThrowable != NULL)
// Does the throwable have buckets?
U1ARRAYREF refWatsonBucketArray = ((EXCEPTIONREF)oThrowable)->GetWatsonBucketReference();
if (refWatsonBucketArray != NULL)
{
// Does the throwable have buckets?
U1ARRAYREF refWatsonBucketArray = ((EXCEPTIONREF)oThrowable)->GetWatsonBucketReference();
if (refWatsonBucketArray != NULL)
{
// Get the watson buckets from the throwable for non-preallocated
// exceptions
pBuckets = dac_cast<PTR_VOID>(refWatsonBucketArray->GetDataPtr());
}
else
// Get the watson buckets from the throwable for non-preallocated
// exceptions
pBuckets = dac_cast<PTR_VOID>(refWatsonBucketArray->GetDataPtr());
}
else
{
// This is a preallocated exception object - check if the UE Watson bucket tracker
// has any bucket details
pBuckets = pThread->GetExceptionState()->GetUEWatsonBucketTracker()->RetrieveWatsonBuckets();
if (pBuckets == NULL)
{
// This is a preallocated exception object - check if the UE Watson bucket tracker
// has any bucket details
pBuckets = pThread->GetExceptionState()->GetUEWatsonBucketTracker()->RetrieveWatsonBuckets();
if (pBuckets == NULL)
// Since the UE watson bucket tracker does not have them, look up the current
// exception tracker
if (pThread->GetExceptionState()->GetCurrentExceptionTracker() != NULL)
{
// Since the UE watson bucket tracker does not have them, look up the current
// exception tracker
if (pThread->GetExceptionState()->GetCurrentExceptionTracker() != NULL)
{
pBuckets = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetWatsonBucketTracker()->RetrieveWatsonBuckets();
}
pBuckets = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetWatsonBucketTracker()->RetrieveWatsonBuckets();
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions src/coreclr/debug/daccess/task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4556,13 +4556,17 @@ ClrDataExceptionState::GetPrevious(
{
if (m_prevExInfo)
{
// Pass the address of the ExInfo's m_exception field as the "handle".
// This is not a real GC handle — it is a target address of an OBJECTREF
// slot on the stack. It has the same lifetime as the ExInfo (both are
// invalidated by PopExInfos/ReleaseResources). See dacimpl.h comment.
*exState = new (nothrow)
ClrDataExceptionState(m_dac,
m_appDomain,
m_thread,
CLRDATA_EXCEPTION_DEFAULT,
m_prevExInfo,
m_prevExInfo->m_hThrowable,
(OBJECTHANDLE)dac_cast<TADDR>(&m_prevExInfo->m_exception),
m_prevExInfo->m_pPrevNestedInfo);
status = *exState ? S_OK : E_OUTOFMEMORY;
}
Expand Down Expand Up @@ -4920,13 +4924,15 @@ ClrDataExceptionState::NewFromThread(ClrDataAccess* dac,

exState = thread->GetExceptionState()->m_pCurrentTracker;

// Pass the address of the ExInfo's m_exception field as the "handle".
// See dacimpl.h comment on the throwable parameter.
exIf = new (nothrow)
ClrDataExceptionState(dac,
AppDomain::GetCurrentDomain(),
thread,
CLRDATA_EXCEPTION_DEFAULT,
exState,
exState->m_hThrowable,
(OBJECTHANDLE)dac_cast<TADDR>(&exState->m_exception),
exState->m_pPrevNestedInfo);
if (!exIf)
{
Expand Down
11 changes: 7 additions & 4 deletions src/coreclr/debug/ee/debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7867,11 +7867,14 @@ BOOL Debugger::ShouldSendCatchHandlerFound(Thread* pThread)
else
{
BOOL forceSendCatchHandlerFound = FALSE;
OBJECTHANDLE objHandle = pThread->GetThrowableAsHandle();
OBJECTHANDLE retrievedHandle = m_pForceCatchHandlerFoundEventsTable->Lookup(objHandle); //destroy handle
if (retrievedHandle != NULL)
OBJECTHANDLE objHandle = pThread->m_LastThrownObjectHandle;
if (objHandle != NULL)
{
forceSendCatchHandlerFound = TRUE;
OBJECTHANDLE retrievedHandle = m_pForceCatchHandlerFoundEventsTable->Lookup(objHandle);
if (retrievedHandle != NULL)
{
forceSendCatchHandlerFound = TRUE;
}
}
return forceSendCatchHandlerFound;
}
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ CDAC_TYPE_END(Exception)
CDAC_TYPE_BEGIN(ExceptionInfo)
CDAC_TYPE_INDETERMINATE(ExceptionInfo)
CDAC_TYPE_FIELD(ExceptionInfo, T_POINTER, PreviousNestedInfo, offsetof(ExInfo, m_pPrevNestedInfo))
CDAC_TYPE_FIELD(ExceptionInfo, TYPE(ObjectHandle), ThrownObjectHandle, offsetof(ExInfo, m_hThrowable))
CDAC_TYPE_FIELD(ExceptionInfo, T_POINTER, ThrownObject, offsetof(ExInfo, m_exception))
CDAC_TYPE_FIELD(ExceptionInfo, T_UINT32, ExceptionFlags, cdac_data<ExInfo>::ExceptionFlagsValue)
CDAC_TYPE_FIELD(ExceptionInfo, T_POINTER, StackLowBound, cdac_data<ExInfo>::StackLowBound)
CDAC_TYPE_FIELD(ExceptionInfo, T_POINTER, StackHighBound, cdac_data<ExInfo>::StackHighBound)
Expand Down
31 changes: 9 additions & 22 deletions src/coreclr/vm/eedbginterfaceimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,16 @@ OBJECTHANDLE EEDbgInterfaceImpl::GetThreadException(Thread *pThread)
}
CONTRACTL_END;

OBJECTHANDLE oh = pThread->GetThrowableAsHandle();

if (oh != NULL)
// The exception object is stored directly in ExInfo::m_exception (no handle).
// Return m_LastThrownObjectHandle which is kept in sync via SafeSetThrowables
// before any debugger notification fires. Assert this invariant in debug builds.
#ifdef _DEBUG
ExInfo* pTracker = pThread->GetExceptionState()->GetCurrentExceptionTracker();
if (pTracker != NULL && pTracker->m_exception != NULL && pThread->m_LastThrownObjectHandle != NULL)
{
return oh;
_ASSERTE(ObjectFromHandle(pThread->m_LastThrownObjectHandle) == pTracker->m_exception);
}

// Return the last thrown object if there's no current throwable.
// This logic is similar to UpdateCurrentThrowable().
#endif
return pThread->m_LastThrownObjectHandle;
}

Expand All @@ -261,21 +262,7 @@ bool EEDbgInterfaceImpl::IsThreadExceptionNull(Thread *pThread)
}
CONTRACTL_END;

//
// We're assuming that the handle on the
// thread is a strong handle and we're goona check it for
// NULL. We're also assuming something about the
// implementation of the handle here, too.
//
OBJECTHANDLE h = pThread->GetThrowableAsHandle();
if (h == NULL)
{
return true;
}

void *pThrowable = *((void**)h);

return (pThrowable == NULL);
return pThread->IsThrowableNull() && pThread->IsLastThrownObjectNull();
}

void EEDbgInterfaceImpl::ClearThreadException(Thread *pThread)
Expand Down
3 changes: 1 addition & 2 deletions src/coreclr/vm/eepolicy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,8 +789,7 @@ void DECLSPEC_NORETURN EEPolicy::HandleFatalStackOverflow(EXCEPTION_POINTERS *pE
OBJECTHANDLE ohSO = CLRException::GetPreallocatedStackOverflowExceptionHandle();
if (ohSO != NULL)
{
pThread->SafeSetThrowables(ObjectFromHandle(ohSO)
DEBUG_ARG(ThreadExceptionState::STEC_CurrentTrackerEqualNullOkHackForFatalStackOverflow),
pThread->SafeSetThrowables(ObjectFromHandle(ohSO),
TRUE);
}
else
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/vm/excep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1849,7 +1849,7 @@ BOOL IsInFirstFrameOfHandler(Thread *pThread, IJitManager *pJitManager, const ME
CONTRACTL_END;

// if don't have a throwable the aren't processing an exception
if (IsHandleNullUnchecked(pThread->GetThrowableAsHandle()))
if (pThread->IsThrowableNull())
return FALSE;

EH_CLAUSE_ENUMERATOR pEnumState;
Expand Down Expand Up @@ -2572,7 +2572,7 @@ void StackTraceInfo::AppendElement(OBJECTHANDLE hThrowable, UINT_PTR currentIP,
LOG((LF_EH, LL_INFO10000, "StackTraceInfo::AppendElement IP = %p, SP = %p, %s::%s\n", currentIP, currentSP, pFunc ? pFunc->m_pszDebugClassName : "", pFunc ? pFunc->m_pszDebugMethodName : "" ));

// Do not save stacktrace to preallocated exception. These are shared.
if (CLRException::IsPreallocatedExceptionHandle(hThrowable))
if (CLRException::IsPreallocatedExceptionObject(ObjectFromHandle(hThrowable)))
{
return;
}
Expand Down
28 changes: 14 additions & 14 deletions src/coreclr/vm/exceptionhandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,9 @@ BOOL HandleHardwareException(PAL_SEHException* ex)
exInfo.TakeExceptionPointersOwnership(ex);
}

GCPROTECT_BEGIN(exInfo.m_exception);
// m_exception is GC-reported via ExInfo chain scanning in ScanStackRoots.
// Do NOT also GCPROTECT it — reporting the same location twice corrupts
// the GC's relocation logic (see clr-code-guide.md §2.1.5).
UnmanagedCallersOnlyCaller throwHwEx(METHOD__EH__RH_THROWHW_EX);

pThread->IncPreventAbort();
Expand All @@ -1457,8 +1459,6 @@ BOOL HandleHardwareException(PAL_SEHException* ex)

DispatchExSecondPass(&exInfo);

GCPROTECT_END();

UNREACHABLE();
}
else
Expand Down Expand Up @@ -1620,8 +1620,9 @@ VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, CONTEXT* pE
}
}

GCPROTECT_BEGIN(exInfo.m_exception);

// m_exception is GC-reported via ExInfo chain scanning in ScanStackRoots.
// Do NOT also GCPROTECT it — reporting the same location twice corrupts
// the GC's relocation logic (see clr-code-guide.md §2.1.5).
UnmanagedCallersOnlyCaller throwEx(METHOD__EH__RH_THROW_EX);

pThread->IncPreventAbort();
Expand All @@ -1631,7 +1632,6 @@ VOID DECLSPEC_NORETURN DispatchManagedException(OBJECTREF throwable, CONTEXT* pE

DispatchExSecondPass(&exInfo);

GCPROTECT_END();
GCPROTECT_END();

UNREACHABLE();
Expand Down Expand Up @@ -1674,7 +1674,9 @@ VOID DECLSPEC_NORETURN DispatchRethrownManagedException(CONTEXT* pExceptionConte

ExInfo exInfo(pThread, pActiveExInfo->m_ptrs.ExceptionRecord, pExceptionContext, ExKind::None);

GCPROTECT_BEGIN(exInfo.m_exception);
// m_exception is GC-reported via ExInfo chain scanning in ScanStackRoots.
// Do NOT also GCPROTECT it — reporting the same location twice corrupts
// the GC's relocation logic (see clr-code-guide.md §2.1.5).
UnmanagedCallersOnlyCaller rethrow(METHOD__EH__RH_RETHROW);

pThread->IncPreventAbort();
Expand All @@ -1683,8 +1685,6 @@ VOID DECLSPEC_NORETURN DispatchRethrownManagedException(CONTEXT* pExceptionConte
rethrow.InvokeDirect(pActiveExInfo, &exInfo);
DispatchExSecondPass(&exInfo);

GCPROTECT_END();

UNREACHABLE();
}

Expand Down Expand Up @@ -2922,7 +2922,7 @@ ExInfo::StackRange::StackRange()
void ExInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
{
// ExInfo is embedded so don't enum 'this'.
OBJECTHANDLE_EnumMemoryRegions(m_hThrowable);
OBJECTREF_EnumMemoryRegions(m_exception);
m_ptrs.ExceptionRecord.EnumMem();
m_ptrs.ContextRecord.EnumMem();
}
Expand Down Expand Up @@ -2973,7 +2973,7 @@ extern "C" void QCALLTYPE AppendExceptionStackFrame(QCall::ObjectHandleOnStack e
_ASSERTE(pMD == codeInfo.GetMethodDesc());
#endif // _DEBUG

StackTraceInfo::AppendElement(pExInfo->m_hThrowable, ip, sp, pMD, &pExInfo->m_frameIter.m_crawl);
StackTraceInfo::AppendElement((OBJECTHANDLE)&pExInfo->m_exception, ip, sp, pMD, &pExInfo->m_frameIter.m_crawl);
}
}

Expand Down Expand Up @@ -3772,7 +3772,7 @@ CLR_BOOL SfiInitWorker(StackFrameIterator* pThis, CONTEXT* pStackwalkCtx, CLR_BO
if (pMD != NULL)
{
GCX_COOP();
StackTraceInfo::AppendElement(pExInfo->m_hThrowable, 0, GetRegdisplaySP(pExInfo->m_frameIter.m_crawl.GetRegisterSet()), pMD, &pExInfo->m_frameIter.m_crawl);
StackTraceInfo::AppendElement((OBJECTHANDLE)&pExInfo->m_exception, 0, GetRegdisplaySP(pExInfo->m_frameIter.m_crawl.GetRegisterSet()), pMD, &pExInfo->m_frameIter.m_crawl);

#if defined(DEBUGGING_SUPPORTED)
if (NotifyDebuggerOfStub(pThread, pFrame))
Expand Down Expand Up @@ -3954,7 +3954,7 @@ CLR_BOOL SfiNextWorker(StackFrameIterator* pThis, uint* uExCollideClauseIdx, CLR
void* callbackCxt = NULL;
Interop::ManagedToNativeExceptionCallback callback = Interop::GetPropagatingExceptionCallback(
&codeInfo,
pTopExInfo->m_hThrowable,
pTopExInfo->m_exception,
&callbackCxt);

if (callback != NULL)
Expand Down Expand Up @@ -4091,7 +4091,7 @@ CLR_BOOL SfiNextWorker(StackFrameIterator* pThis, uint* uExCollideClauseIdx, CLR
if (pMD != NULL)
{
GCX_COOP();
StackTraceInfo::AppendElement(pTopExInfo->m_hThrowable, 0, GetRegdisplaySP(pTopExInfo->m_frameIter.m_crawl.GetRegisterSet()), pMD, &pTopExInfo->m_frameIter.m_crawl);
StackTraceInfo::AppendElement((OBJECTHANDLE)&pTopExInfo->m_exception, 0, GetRegdisplaySP(pTopExInfo->m_frameIter.m_crawl.GetRegisterSet()), pMD, &pTopExInfo->m_frameIter.m_crawl);

#if defined(DEBUGGING_SUPPORTED)
if (NotifyDebuggerOfStub(pThread, pFrame))
Expand Down
Loading
Loading