Skip to content
Merged
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
12 changes: 5 additions & 7 deletions src/coreclr/vm/assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,10 @@ Assembly * Assembly::Create(
PRECONDITION(pLoaderAllocator != NULL);
PRECONDITION(pLoaderAllocator->IsCollectible() || pLoaderAllocator == SystemDomain::GetGlobalLoaderAllocator());
}
CONTRACTL_END
CONTRACTL_END;

// Validate the assembly about to be created is suitable for execution.
pPEAssembly->ValidateForExecution();

NewHolder<Assembly> pAssembly (new Assembly(pPEAssembly, pLoaderAllocator));

Expand Down Expand Up @@ -540,21 +543,16 @@ Assembly *Assembly::CreateDynamic(AssemblyBinder* pBinder, NativeAssemblyNamePar
RETURN pRetVal;
} // Assembly::CreateDynamic



void Assembly::SetDomainAssembly(DomainAssembly *pDomainAssembly)
{
CONTRACTL
{
STANDARD_VM_CHECK;
PRECONDITION(CheckPointer(pDomainAssembly));
THROWS;
GC_TRIGGERS;
INJECT_FAULT(COMPlusThrowOM(););
}
CONTRACTL_END;

GetModule()->SetDomainAssembly(pDomainAssembly);

} // Assembly::SetDomainAssembly

#endif // #ifndef DACCESS_COMPILE
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/vm/assembly.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,10 @@ class Assembly

//****************************************************************************************

private:
Assembly();

public:
~Assembly();

BOOL GetResource(LPCSTR szName, DWORD *cbResource,
Expand Down
10 changes: 2 additions & 8 deletions src/coreclr/vm/domainassembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,17 @@ DomainAssembly::DomainAssembly(PEAssembly* pPEAssembly, LoaderAllocator* pLoader
{
CONTRACTL
{
STANDARD_VM_CHECK;
CONSTRUCTOR_CHECK;
THROWS; // ValidateForExecution
GC_TRIGGERS; // ValidateForExecution
MODE_ANY;
}
CONTRACTL_END;

pPEAssembly->AddRef();
pPEAssembly->ValidateForExecution();

// Create the Assembly
NewHolder<Assembly> assembly = Assembly::Create(pPEAssembly, memTracker, pLoaderAllocator);
assembly->SetDomainAssembly(this);

m_pAssembly = assembly.Extract();

m_pAssembly->SetDomainAssembly(this);

#ifndef PEIMAGE_FLAT_LAYOUT_ONLY
// Creating the Assembly should have ensured the PEAssembly is loaded
_ASSERT(GetPEAssembly()->IsLoaded());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Needed for GC.WaitForPendingFinalizers -->
<RequiresProcessIsolation>true</RequiresProcessIsolation>
<GCStressIncompatible>true</GCStressIncompatible>
<UnloadabilityIncompatible>true</UnloadabilityIncompatible>
<!-- Collectible ALCs are not supported -->
<NativeAotIncompatible>true</NativeAotIncompatible>
<CLRTestTargetUnsupported Condition="'$(RuntimeFlavor)' != 'coreclr'">true</CLRTestTargetUnsupported>
</PropertyGroup>
<ItemGroup>
<Compile Include="Program.cs" />
</ItemGroup>
</Project>
97 changes: 97 additions & 0 deletions src/tests/Loader/CollectibleAssemblies/AssemblyOnDisk/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
using Xunit;

public class Program
{
[Fact]
public static void EntryPoint()
{
string directoryPath = Path.Combine(AppContext.BaseDirectory, "ToDelete");
string originalAssemblyPath = typeof(Program).Assembly.Location;
string newAssemblyPath = Path.Combine(directoryPath, Path.GetFileName(originalAssemblyPath));

// If the directory already exists, delete it
if (Directory.Exists(directoryPath))
{
Console.WriteLine("Temp directory already exists, deleting...");
Directory.Delete(directoryPath, true);
}

// Create a directory to copy the assembly to
Directory.CreateDirectory(directoryPath);
try
{
File.Copy(originalAssemblyPath, newAssemblyPath);

UnloadableAssemblyContext assemblyContext = UnloadableAssemblyContext.Create();
assemblyContext.RunWithAssemblyLoadContext(
context =>
{
context.LoadFromAssemblyPath(newAssemblyPath);
});

assemblyContext.Unload();
}
finally
{
Directory.Delete(directoryPath, recursive: true);
}

Assert.False(Directory.Exists(directoryPath));
}

class UnloadableAssemblyContext
{
private readonly WeakReference _weakAssemblyLoadContextReference;

private AssemblyLoadContext? _assemblyLoadContext;

private UnloadableAssemblyContext()
{
_assemblyLoadContext = new AssemblyLoadContext("AssemblyOnDiskTest", isCollectible: true);
_weakAssemblyLoadContextReference = new WeakReference(_assemblyLoadContext, trackResurrection: true);
}

[MethodImpl(MethodImplOptions.NoInlining)]
public static UnloadableAssemblyContext Create()
{
return new UnloadableAssemblyContext();
}

[MethodImpl(MethodImplOptions.NoInlining)]
public void RunWithAssemblyLoadContext(Action<AssemblyLoadContext> action)
{
action(_assemblyLoadContext!);
}

public void Unload()
{
TriggerUnload();

const int maxRetries = 32;
for (int i = 0; _weakAssemblyLoadContextReference.IsAlive && i <= maxRetries; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();

if (i == maxRetries)
{
Assert.Fail("Could not unload AssemblyLoadContext.");
}
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void TriggerUnload()
{
_assemblyLoadContext!.Unload();
_assemblyLoadContext = null;
}
}
}
Loading