Repository navigation
AV in GetITypeInfoForMT #75035
Copy link
Copy link
Closed
Labels
Milestone
Description
See #74977 (reply in thread) for context
[Inline Frame] coreclr.dll!InterlockedCompareExchangeT(ITypeInfo * volatile *) Line 4341
[Inline Frame] coreclr.dll!InterlockedCompareExchangeT(ITypeInfo * volatile *) Line 4375
[Inline Frame] coreclr.dll!InterlockedCompareExchangeT(ITypeInfo * volatile *) Line 4406
[Inline Frame] coreclr.dll!ComMethodTable::SetITypeInfo(ITypeInfo * pNew=0x000001efb0d30fe8) Line 3853
coreclr.dll!GetITypeInfoForMT(ComMethodTable * pMT=0x00007ffd575cf440, ITypeInfo * * ppTI=0x0000001d1d17c308) Line 805
coreclr.dll!DispatchEx_GetTypeInfo(IDispatch * pDisp=0x0000001d1d17c258, unsigned int pptinfo=0x0000001d1d17c308, unsigned long) Line 1547
coreclr.dll!DispatchEx_GetTypeInfo_CallBack(void * ptr=0x0000001d1d17c258) Line 1281
coreclr.dll!DispatchEx_GetTypeInfo_Wrapper(IDispatchEx * pDisp=0x00000230477a6740, unsigned int itinfo=0x00000000, unsigned long lcid=0x00000000, ITypeInfo * * pptinfo=0x0000001d1d17c308) Line 1306
jscript.dll!JAmsi::JAmsiProcessor()
jscript.dll!VAR::InvokeByDispID()
jscript.dll!NameTbl::InvokeInternal()
jscript.dll!VAR::InvokeByDispID()
jscript.dll!CScriptRuntime::Run(class VAR *)
jscript.dll!ScrFncObj::PerformCall(class CScriptRuntime *,class VAR *,int,class VAR *,class VAR *,unsigned long)
jscript.dll!ScrFncObj::CallWithFrameOnStack(class VAR *,int,class VAR *,class VAR *,unsigned long)
jscript.dll!ScrFncObj::Call()
jscript.dll!JsEval()
jscript.dll!NatFncObj::Call()
jscript.dll!NameTbl::InvokeInternal()
jscript.dll!VAR::InvokeByDispID()
jscript.dll!CScriptRuntime::Run(class VAR *)
jscript.dll!ScrFncObj::PerformCall(class CScriptRuntime *,class VAR *,int,class VAR *,class VAR *,unsigned long)
jscript.dll!ScrFncObj::CallWithFrameOnStack(class VAR *,int,class VAR *,class VAR *,unsigned long)
jscript.dll!ScrFncObj::Call()
jscript.dll!CSession::Execute(class NameTbl *,struct tagVARIANT *,int,struct tagVARIANT *,struct tagVARIANT *,unsigned long)
jscript.dll!COleScript::ExecutePendingScripts()
jscript.dll!COleScript::ParseScriptTextCore()
jscript.dll!COleScript::ParseScriptText(unsigned short const *,unsigned short const *,struct IUnknown *,unsigned short const *,unsigned __int64,unsigned long,unsigned long,struct tagVARIANT *,struct tagEXCEPINFO *)
The debugger is pointing at the following source line in ...\src\coreclr\inc\utilcode.h
template <typename T>
inline T* InterlockedCompareExchangeT(
T* volatile * destination,
T* exchange,
T* comparand)
{
//STATIC_ASSERT(exchange == 0);
typedef typename std::remove_const<T>::type * non_const_ptr_t;
--> return reinterpret_cast<T*>(InterlockedCompareExchangePointer(
reinterpret_cast<PVOID volatile *>(const_cast<non_const_ptr_t volatile *>(destination)),
reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(exchange)),
reinterpret_cast<PVOID>(const_cast<non_const_ptr_t>(comparand))));
}Here's what the disassembler has to say:
// Returns a NON-ADDREF'd ITypeInfo.
HRESULT GetITypeInfoForMT(ComMethodTable *pMT, ITypeInfo **ppTI)
{
mov r11,rsp
mov qword ptr [r11+10h],rbx
mov qword ptr [r11+18h],rsi
push rdi
sub rsp,20h
CONTRACTL
{
NOTHROW;
GC_TRIGGERS;
MODE_PREEMPTIVE;
PRECONDITION(CheckPointer(pMT));
PRECONDITION(CheckPointer(ppTI));
}
CONTRACTL_END;
HRESULT hr = S_OK; // A result.
ITypeInfo *pTI; // The ITypeInfo.
pTI = pMT->GetITypeInfo();
mov rax,qword ptr [rcx+28h]
xor edi,edi
mov qword ptr [r11+8],rax
mov rsi,rdx
mov rbx,rcx
test rax,rax
if (pTI == NULL)
jne GetITypeInfoForMT+64h (07FFDB740A954h)
{
MethodTable *pClass = pMT->GetMethodTable();
hr = GetITypeInfoForEEClass(pClass, &pTI);
mov rcx,qword ptr [rcx+8]
lea rdx,[r11+8]
xor r8d,r8d
call GetITypeInfoForEEClass (07FFDB7409A70h)
mov edi,eax
if (SUCCEEDED(hr))
test eax,eax
js GetITypeInfoForMT+5Fh (07FFDB740A94Fh)
{
pMT->SetITypeInfo(pTI);
mov rcx,qword ptr [pTI]
xor eax,eax
--> lock cmpxchg qword ptr [rbx+28h],rcx
jne GetITypeInfoForMT+4Fh (07FFDB740A93Fh)
call SafeAddRef (07FFDB711731Ch)
SafeReleasePreemp(pTI);
mov rcx,qword ptr [pTI]
call SafeReleasePreemp (07FFDB7119290h)
pTI = pMT->GetITypeInfo();
mov rax,qword ptr [rbx+28h]
jmp GetITypeInfoForMT+64h (07FFDB740A954h)
if (SUCCEEDED(hr))
mov rax,qword ptr [pTI]
}
}
*ppTI = pTI;
return hr;
}
mov rbx,qword ptr [rsp+38h]
mov qword ptr [rsi],rax
mov eax,edi
mov rsi,qword ptr [rsp+40h]
add rsp,20h
pop rdi
ret
Just for completeness, [rbx+28h] is pointing at two consecutive 64-bit nulls followed by other data.
One other bit: The debugger indicates that the access violation is due to an invalid write.
Reactions are currently unavailable
Activity
AaronRobinsonMSFT commentedon Sep 3, 2022
@jkotas Is there any prior art to this? I don't have a full repro but do see the issue in the x86 DMP. Do you know how to check the write status of the page in WinDBG? I'm going to try to figure it out, but any pointers are helpful.
AaronRobinsonMSFT commentedon Sep 3, 2022
@jkotas Seems your intuition is correct.
AaronRobinsonMSFT commentedon Sep 3, 2022
Assuming I should use
ClrVirtualProtect. However, I am not sure the best way to address this in a holistic way as I am dubious this is the only place where we are missing this check. Should I perhaps create a general "get member memory for set" on theComMethodTableor just handle this in a one off for the specificITypeInfoupdate path?jkotas commentedon Sep 3, 2022
ExecutableWriterHolderis the helper you are looking for.