String name,
bool throwOnError,
bool ignoreCase,
- ObjectHandleOnStack type);
+ ObjectHandleOnStack type,
+ ObjectHandleOnStack keepAlive);
[System.Security.SecuritySafeCritical]
public override Type GetType(String name, bool throwOnError, bool ignoreCase)
throw new ArgumentNullException("name");
RuntimeType type = null;
- GetType(GetNativeHandle(), name, throwOnError, ignoreCase, JitHelpers.GetObjectHandleOnStack(ref type));
+ Object keepAlive = null;
+ GetType(GetNativeHandle(), name, throwOnError, ignoreCase, JitHelpers.GetObjectHandleOnStack(ref type), JitHelpers.GetObjectHandleOnStack(ref keepAlive));
+ GC.KeepAlive(keepAlive);
+
return type;
}
[System.Security.SecurityCritical] // auto-generated
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
- private extern static void GetType(RuntimeModule module, String className, bool ignoreCase, bool throwOnError, ObjectHandleOnStack type);
+ private extern static void GetType(RuntimeModule module, String className, bool ignoreCase, bool throwOnError, ObjectHandleOnStack type, ObjectHandleOnStack keepAlive);
[System.Security.SecurityCritical]
[DllImport(JitHelpers.QCall)]
throw new ArgumentNullException("className");
RuntimeType retType = null;
- GetType(GetNativeHandle(), className, throwOnError, ignoreCase, JitHelpers.GetObjectHandleOnStack(ref retType));
+ Object keepAlive = null;
+ GetType(GetNativeHandle(), className, throwOnError, ignoreCase, JitHelpers.GetObjectHandleOnStack(ref retType), JitHelpers.GetObjectHandleOnStack(ref keepAlive));
+ GC.KeepAlive(keepAlive);
return retType;
}
#if FEATURE_HOSTED_BINDER
IntPtr pPrivHostBinder,
#endif
- bool loadTypeFromPartialName, ObjectHandleOnStack type);
+ bool loadTypeFromPartialName, ObjectHandleOnStack type, ObjectHandleOnStack keepalive);
#if FEATURE_HOSTED_BINDER
// Wrapper function to reduce the need for ifdefs.
RuntimeType type = null;
+ Object keepAlive = null;
GetTypeByName(name, throwOnError, ignoreCase, reflectionOnly,
JitHelpers.GetStackCrawlMarkHandle(ref stackMark),
#if FEATURE_HOSTED_BINDER
pPrivHostBinder,
#endif
- loadTypeFromPartialName, JitHelpers.GetObjectHandleOnStack(ref type));
+ loadTypeFromPartialName, JitHelpers.GetObjectHandleOnStack(ref type), JitHelpers.GetObjectHandleOnStack(ref keepAlive));
+ GC.KeepAlive(keepAlive);
return type;
}
}
FCIMPLEND
-void QCALLTYPE AssemblyNative::GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType)
+void QCALLTYPE AssemblyNative::GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive)
{
CONTRACTL
{
if (!wszName)
COMPlusThrowArgumentNull(W("name"), W("ArgumentNull_String"));
- GCX_COOP();
-
- OBJECTREF keepAlive = NULL;
- GCPROTECT_BEGIN(keepAlive);
-
- {
- GCX_PREEMP();
+ BOOL prohibitAsmQualifiedName = TRUE;
- BOOL prohibitAsmQualifiedName = TRUE;
-
- // Load the class from this assembly (fail if it is in a different one).
- retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, pAssembly->IsIntrospectionOnly(), prohibitAsmQualifiedName, NULL, FALSE, &keepAlive);
- }
+ // Load the class from this assembly (fail if it is in a different one).
+ retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, pAssembly->IsIntrospectionOnly(), prohibitAsmQualifiedName, NULL, FALSE, (OBJECTREF*)keepAlive.m_ppObject);
if (!retTypeHandle.IsNull())
{
- retType.Set(retTypeHandle.GetManagedClassObject());
+ GCX_COOP();
+ retType.Set(retTypeHandle.GetManagedClassObject());
}
- GCPROTECT_END();
-
END_QCALL;
return;
QCall::ObjectHandleOnStack retModule);
static
- void QCALLTYPE GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType);
+ void QCALLTYPE GetType(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive);
static
INT32 QCALLTYPE GetManifestResourceInfo(QCall::AssemblyHandle pAssembly, LPCWSTR wszName, QCall::ObjectHandleOnStack retAssembly, QCall::StringHandleOnStack retFileName, QCall::StackCrawlMarkHandle stackMark);
// GetType
// Given a class name, this method will look for that class
// with in the module.
-void QCALLTYPE COMModule::GetType(QCall::ModuleHandle pModule, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType)
+void QCALLTYPE COMModule::GetType(QCall::ModuleHandle pModule, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive)
{
CONTRACTL
{
BEGIN_QCALL;
- GCX_COOP();
-
DomainAssembly *pAssembly = pModule->GetDomainAssembly();
_ASSERTE(pAssembly);
- OBJECTREF keepAlive = NULL;
- GCPROTECT_BEGIN(keepAlive);
-
- {
- GCX_PREEMP();
-
- BOOL prohibitAsmQualifiedName = TRUE;
+ BOOL prohibitAsmQualifiedName = TRUE;
- // Load the class from this assembly (fail if it is in a different one).
- retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, pAssembly->IsIntrospectionOnly(), prohibitAsmQualifiedName, NULL, FALSE, &keepAlive);
- }
+ // Load the class from this assembly (fail if it is in a different one).
+ retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, pAssembly->IsIntrospectionOnly(), prohibitAsmQualifiedName, NULL, FALSE, (OBJECTREF*)keepAlive.m_ppObject);
// Verify that it's in 'this' module
// But, if it's in a different assembly than expected, that's okay, because
GCX_COOP();
retType.Set(retTypeHandle.GetManagedClassObject());
}
- GCPROTECT_END();
-
+
END_QCALL;
return;
// Given a class type, this method will look for that type
// with in the module.
static
- void QCALLTYPE GetType(QCall::ModuleHandle pModule, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType);
+ void QCALLTYPE GetType(QCall::ModuleHandle pModule, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive);
// Get class will return an array contain all of the classes
// that are defined within this Module.
// policy here. Do we want to let such funcitons throw, etc.? Right now, we believe that there are no such
// frames on the stack to be unwound, so the SetFrame is alright (see the first comment above.) At the very
// least, we should add some way to assert that.
- //
- // ~FrameWithCookieHolder is also calling SetFrame() and if UnwindAndContinueRethrowHelperInsideCatch is ever changed
- // to not call SetFrame then the change should be reflected in the FrameWithCookieHolder as well.
- //
pThread->SetFrame(pEntryFrame);
#ifdef _DEBUG
DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(SecurityContextFrame)
};
-
-// This holder is defined for addressing a very specific issue:
-// Frames that use GCPROTECT_BEGIN/GCPROTECT_END can end up referencing corrupted object refs
-// when an exception is thrown until the point where the Frame is actually popped from the thread's Frame-chain.
-// Stack space allocated for OBJECTREFs in a try block may be reused in the catch block by other structures,
-// corrupting our protected OBJECTREFs and the Frame containing them. While the Frame is still on the callstack
-// a GC may occur, detecting the corrupt OBJECTREF and taking down the process. The FrameWithCookieHolder
-// forces the Frame to be popped out when exiting the current scope, therefore before the OBJECTREF is corrupted.
-//
-// This holder explicitly calls Thread::SetFrame, therefore potentially removing Frames from the thread's frame
-// chain without properly calling their corresponding ExceptionUnwind() method. This is extremely dangerous to
-// use unless it is backed by a call to UnwindAndContinueRethrowHelperInsideCatch() which does the same thing
-// (and has been vetted to be correct in doing so). Using this holder in any other circumstances may lead to bugs that
-// are extremely difficult to track down.
-template <typename TYPE>
-class FrameWithCookieHolder
-{
- protected:
- FrameWithCookie<TYPE> m_frame;
-
- public:
- FORCEINLINE FrameWithCookieHolder()
- : m_frame()
- {
- }
-
- // GCFrame
- FORCEINLINE FrameWithCookieHolder(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
- : m_frame(pObjRefs, numObjRefs, maybeInterior)
- {
- }
-
- FORCEINLINE ~FrameWithCookieHolder()
- {
-#ifndef DACCESS_COMPILE
-
- Thread* pThread = GetThread();
- if (pThread)
- {
- GCX_COOP();
- pThread->SetFrame(&m_frame);
- m_frame.Pop();
- }
-
-#endif // #ifndef DACCESS_COMPILE
- }
-
-};
-
-#ifndef DACCESS_COMPILE
-// Restrictions from FrameWithCookieHolder are also applying for GCPROTECT_HOLDER.
-// Please read the FrameWithCookieHolder comments before using GCPROTECT_HOLDER.
-#define GCPROTECT_HOLDER(ObjRefStruct) \
- FrameWithCookieHolder<GCFrame> __gcframe((OBJECTREF*)&(ObjRefStruct), \
- sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
- FALSE);
-
-#else // #ifndef DACCESS_COMPILE
-
-#define GCPROTECT_HOLDER(ObjRefStruct)
-
-#endif // #ifndef DACCESS_COMPILE
-
-
//------------------------------------------------------------------------
// These macros GC-protect OBJECTREF pointers on the EE's behalf.
// In between these macros, the GC can move but not discard the protected
#ifdef FEATURE_HOSTED_BINDER
ICLRPrivBinder * pPrivHostBinder,
#endif
- BOOL bLoadTypeFromPartialNameHack, QCall::ObjectHandleOnStack retType)
+ BOOL bLoadTypeFromPartialNameHack, QCall::ObjectHandleOnStack retType,
+ QCall::ObjectHandleOnStack keepAlive)
{
QCALL_CONTRACT;
if (!pwzClassName)
COMPlusThrowArgumentNull(W("className"),W("ArgumentNull_String"));
- GCX_COOP();
{
- OBJECTREF keepAlive = NULL;
-
- // BEGIN_QCALL/END_QCALL define try/catch scopes for potential exceptions thrown when bThrowOnError is enabled.
- // Originally, in case of an exception the GCFrame was removed from the Thread's Frame chain in the catch block, in UnwindAndContinueRethrowHelperInsideCatch.
- // However, the catch block declared some local variables that overlapped the location of the now out of scope GCFrame and OBJECTREF, therefore corrupting
- // those values. Having the GCX_COOP/GCX_PREEMP switching GC modes, allowed a situation where in case of an exception, the thread would wait for a GC to complete
- // while still having the GCFrame in the Thread's Frame chain, but with a corrupt OBJECTREF due to stack location reuse in the catch block.
- // The solution is to force the removal of GCFrame (and the Frames above) from the Thread's Frame chain before entering the catch block, at the time of
- // FrameWithCookieHolder's destruction.
- GCPROTECT_HOLDER(keepAlive);
-
- {
- GCX_PREEMP();
- typeHandle = TypeName::GetTypeManaged(pwzClassName, NULL, bThrowOnError, bIgnoreCase, bReflectionOnly, /*bProhibitAsmQualifiedName =*/ FALSE, pStackMark, bLoadTypeFromPartialNameHack, &keepAlive
+ typeHandle = TypeName::GetTypeManaged(pwzClassName, NULL, bThrowOnError, bIgnoreCase, bReflectionOnly, /*bProhibitAsmQualifiedName =*/ FALSE, pStackMark,
+ bLoadTypeFromPartialNameHack, (OBJECTREF*)keepAlive.m_ppObject
#ifdef FEATURE_HOSTED_BINDER
- , pPrivHostBinder
+ , pPrivHostBinder
#endif
- );
- }
+ );
+ }
- if (!typeHandle.IsNull())
- {
- retType.Set(typeHandle.GetManagedClassObject());
- }
+ if (!typeHandle.IsNull())
+ {
+ GCX_COOP();
+ retType.Set(typeHandle.GetManagedClassObject());
}
END_QCALL;
#ifdef FEATURE_HOSTED_BINDER
ICLRPrivBinder * pPrivHostBinder,
#endif
- BOOL bLoadTypeFromPartialNameHack, QCall::ObjectHandleOnStack retType);
+ BOOL bLoadTypeFromPartialNameHack, QCall::ObjectHandleOnStack retType,
+ QCall::ObjectHandleOnStack keepAlive);
static FCDECL1(AssemblyBaseObject*, GetAssembly, ReflectClassBaseObject *pType);
static FCDECL1(ReflectClassBaseObject*, GetBaseType, ReflectClassBaseObject* pType);