Source code analysis of Core CLR Host

Keywords: network

When CLR instantiates PEAssembly, it calls peassemblyholder pfile (pdomain - > bindassemblyspec (this, ftrowonfilenotfound, fraiseprebindevents, pcallerstackmark));

There are actually three steps:

1. get bindResult through pSpec->Bind (), then call PEAssembly::Open new, a PEAssembly instance, the parameter is bindReuslt.

2. The bind function of pspec will return pPrivAsm. The code is:

   

   hr = pTPABinder->Bind(assemblyDisplayName,
                           m_wszCodeBase,
                           GetParentAssembly()? GetParentAssembly()->GetFile():NULL,
                           fNgenExplicitBind,
                           fExplicitBindToNativeImage,
                          &pPrivAsm);

When pprivasm is returned, pprivasm is passed through the function GetAssemblyFromPrivAssemblyFast,; result = binder_space:: GetAssemblyFromPrivAssemblyFast (privasm. Extract());

Finally, sresult - > init (result, fisingac, fisontpalest); return the bindResult of the previous step

3. The ptabinder - > bind function will call to get the pasm assembly handle. This handle is actually to call binderresult first, then get hostbinderresult through binderresult, and finally return the program pasm through hostbinderresult

4. When getting binderresult, he will instantiate peimage and pasm, and then set binderresult.

 

The specific steps are as follows:

Some codes are as follows:

 if (pSpec->HasUniqueIdentity())
    {
        HRESULT hrBindResult = S_OK;
        PEAssemblyHolder result;
        

        EX_TRY
        {
            if (!IsCached(pSpec))
            {

                {
                    bool fAddFileToCache = false;

                    BOOL fIsWellKnown = FALSE;

                    // Use CoreClr's fusion alternative
                    CoreBindResult bindResult;

                    pSpec->Bind(this, fThrowOnFileNotFound, &bindResult, FALSE /* fNgenExplicitBind */, FALSE /* fExplicitBindToNativeImage */, pCallerStackMark);
                    hrBindResult = bindResult.GetHRBindResult();

                    if (bindResult.Found()) 
                    {
                        if (SystemDomain::SystemFile() && bindResult.IsMscorlib())
                        {
                            // Avoid rebinding to another copy of mscorlib
                            result = SystemDomain::SystemFile();
                            result.SuppressRelease(); // Didn't get a refcount
                        }
                        else
                        {
                            // IsSystem on the PEFile should be false, even for mscorlib satellites
                            result = PEAssembly::Open(&bindResult,
                                                      FALSE, pSpec->IsIntrospectionOnly());
                        }
                        fAddFileToCache = true;
                        
                        // Setup the reference to the binder, which performed the bind, into the AssemblySpec
                        ICLRPrivBinder* pBinder = result->GetBindingContext();
                        _ASSERTE(pBinder != NULL);
                        pSpec->SetBindingContext(pBinder);
                    }


                    if (fAddFileToCache)
                    {


                        if (pSpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
                        {
                            // Failure to add simply means someone else beat us to it. In that case
                            // the FindCachedFile call below (after catch block) will update result
                            // to the cached value.
                            AddFileToCache(pSpec, result, TRUE /*fAllowFailure*/);
                        }
                    }
                    else if (!fIsWellKnown)
                    {
                        _ASSERTE(fThrowOnFileNotFound == FALSE);

                        // Don't trigger the resolve event for the CoreLib satellite assembly. A misbehaving resolve event may
                        // return an assembly that does not match, and this can cause recursive resource lookups during error
                        // reporting. The CoreLib satellite assembly is loaded from relative locations based on the culture, see
                        // AssemblySpec::Bind().
                        if (!pSpec->IsMscorlibSatellite())
                        {
                            // Trigger the resolve event also for non-throw situation.
                            // However, this code path will behave as if the resolve handler has thrown,
                            // that is, not trigger an MDA.

                            AssemblySpec NewSpec(this);
                            AssemblySpec *pFailedSpec = NULL;

                            fForceReThrow = TRUE; // Managed resolve event handler can throw

                            // Purposly ignore return value
                            PostBindResolveAssembly(pSpec, &NewSpec, hrBindResult, &pFailedSpec);
                        }
                    }
                }
            }
        }
        EX_CATCH
        {
            Exception *ex = GET_EXCEPTION();

            AssemblySpec NewSpec(this);
            AssemblySpec *pFailedSpec = NULL;

            // Let transient exceptions or managed resolve event handler exceptions propagate
            if (ex->IsTransient() || fForceReThrow)
            {
                EX_RETHROW;
            }

            {
                // This is not executed for SO exceptions so we need to disable the backout
                // stack validation to prevent false violations from being reported.
                DISABLE_BACKOUT_STACK_VALIDATION;

                BOOL fFailure = PostBindResolveAssembly(pSpec, &NewSpec, ex->GetHR(), &pFailedSpec);
                if (fFailure)
                {
                    BOOL bFileNotFoundException =
                        (EEFileLoadException::GetFileLoadKind(ex->GetHR()) == kFileNotFoundException);
                
                    if (!bFileNotFoundException)
                    {
                        fFailure = AddExceptionToCache(pFailedSpec, ex);
                    } // else, fFailure stays TRUE
                    // Effectively, fFailure == bFileNotFoundException || AddExceptionToCache(pFailedSpec, ex)

                    // Only throw this exception if we are the first in the cache
                    if (fFailure)
                    {
                        //
                        // If the BindingFailure MDA is enabled, trigger one for this failure
                        // Note: TryResolveAssembly() can also throw if an AssemblyResolve event subscriber throws
                        //       and the MDA isn't sent in this case (or for transient failure cases)
                        //
#ifdef MDA_SUPPORTED
                        MdaBindingFailure* pProbe = MDA_GET_ASSISTANT(BindingFailure);
                        if (pProbe)
                        {
                            // Transition to cooperative GC mode before using any OBJECTREFs.
                            GCX_COOP();

                            OBJECTREF exceptionObj = GET_THROWABLE();
                            GCPROTECT_BEGIN(exceptionObj)
                            {
                                pProbe->BindFailed(pFailedSpec, &exceptionObj);
                            }
                            GCPROTECT_END();
                        }
#endif

                        // In the same cases as for the MDA, store the failure information for DAC to read
                        if (IsDebuggerAttached()) {
                            FailedAssembly *pFailed = new FailedAssembly();
                            pFailed->Initialize(pFailedSpec, ex);
                            IfFailThrow(m_failedAssemblies.Append(pFailed));
                        }

                        if (!bFileNotFoundException || fThrowOnFileNotFound)
                        {

                            // V1.1 App-compatibility workaround. See VSW530166 if you want to whine about it.
                            //
                            // In Everett, if we failed to download an assembly because of a broken network cable,
                            // we returned a FileNotFoundException with a COR_E_FILENOTFOUND hr embedded inside
                            // (which would be exposed when marshaled to native.)
                            //
                            // In Whidbey, we now set the more appropriate INET_E_RESOURCE_NOT_FOUND hr. But
                            // the online/offline switch code in VSTO for Everett hardcoded a check for
                            // COR_E_FILENOTFOUND. 
                            //
                            // So now, to keep that code from breaking, we have to remap INET_E_RESOURCE_NOT_FOUND
                            // back to COR_E_FILENOTFOUND. We're doing it here rather down in Fusion so as to affect
                            // the least number of callers.
                            
                            if (ex->GetHR() == INET_E_RESOURCE_NOT_FOUND)
                            {
                                EEFileLoadException::Throw(pFailedSpec, COR_E_FILENOTFOUND, ex);
                            }

                            if (EEFileLoadException::CheckType(ex))
                            {
                                if (pFailedSpec == pSpec)
                                {
                                    EX_RETHROW; //preserve the information
                                }
                                else
                                {
                                    StackSString exceptionDisplayName, failedSpecDisplayName;

                                    ((EEFileLoadException*)ex)->GetName(exceptionDisplayName);
                                    pFailedSpec->GetFileOrDisplayName(0, failedSpecDisplayName);

                                    if (exceptionDisplayName.CompareCaseInsensitive(failedSpecDisplayName) == 0)
                                    {
                                        EX_RETHROW; // Throw the original exception. Otherwise, we'd throw an exception that contains the same message twice.
                                    }
                                }
                            }
                            
                            EEFileLoadException::Throw(pFailedSpec, ex->GetHR(), ex);
                        }

                    }
                }
            }
        }
        EX_END_CATCH(RethrowTerminalExceptions);

        // Now, if it's a cacheable bind we need to re-fetch the result from the cache, as we may have been racing with another
        // thread to store our result.  Note that we may throw from here, if there is a cached exception.
        // This will release the refcount of the current result holder (if any), and will replace
        // it with a non-addref'ed result
        if (pSpec->CanUseWithBindingCache() && (result== NULL || result->CanUseWithBindingCache()))
        {
            result = FindCachedFile(pSpec);

            if (result != NULL)
                result->AddRef();
        }

        return result.Extract();
    }

 

 

 

 

 

 

Posted by GoRide! on Fri, 15 Nov 2019 06:39:11 -0800