- Added try-catch to assembly compilation call.

- Added empty list checks for metadata references building.
- Made ACL cleanup more reliable.
- Updated some GET functions in AssemblyManager to have better reliability and error handling.
This commit is contained in:
MapleWheels
2023-10-26 10:07:01 -04:00
parent e237389ad9
commit 342a6bbcf9
2 changed files with 69 additions and 33 deletions
@@ -260,7 +260,8 @@ public class AssemblyManager
} }
catch (Exception e) catch (Exception e)
{ {
this.OnException?.Invoke($"{nameof(AssemblyManager)}::{nameof(GetTypesByName)}() | Error: {e.Message}", e); this.OnException?.Invoke(
$"{nameof(AssemblyManager)}::{nameof(GetTypesByName)}() | Error: {e.Message}", e);
} }
} }
} }
@@ -309,12 +310,16 @@ public class AssemblyManager
OpsLockLoaded.EnterReadLock(); OpsLockLoaded.EnterReadLock();
try try
{ {
return AssemblyLoadContext.Default.Assemblies return _defaultContextTypes
.SelectMany(a => a.GetSafeTypes()) .Select(kvp => kvp.Value)
.Concat(LoadedACLs .Concat(LoadedACLs
.SelectMany(kvp => kvp.Value.AssembliesTypes.Select(kv => kv.Value))) .SelectMany(kvp => kvp.Value?.AssembliesTypes.Select(kv => kv.Value)))
.ToImmutableList(); .ToImmutableList();
} }
catch
{
return ImmutableList<Type>.Empty;
}
finally finally
{ {
OpsLockLoaded.ExitReadLock(); OpsLockLoaded.ExitReadLock();
@@ -332,8 +337,17 @@ public class AssemblyManager
OpsLockLoaded.EnterReadLock(); OpsLockLoaded.EnterReadLock();
try try
{ {
if (LoadedACLs.IsEmpty)
{
return ImmutableList<LoadedACL>.Empty;
}
return LoadedACLs.Select(kvp => kvp.Value).ToImmutableList(); return LoadedACLs.Select(kvp => kvp.Value).ToImmutableList();
} }
catch
{
return ImmutableList<LoadedACL>.Empty;
}
finally finally
{ {
OpsLockLoaded.ExitReadLock(); OpsLockLoaded.ExitReadLock();
@@ -387,8 +401,18 @@ public class AssemblyManager
return AssemblyLoadingSuccessState.AlreadyLoaded; return AssemblyLoadingSuccessState.AlreadyLoaded;
// compile // compile
var state = acl.Acl.CompileAndLoadScriptAssembly(compiledAssemblyName, syntaxTree, externalMetadataReferences, AssemblyLoadingSuccessState state;
compilationOptions, out var messages, externFileAssemblyRefs); string messages;
try
{
state = acl.Acl.CompileAndLoadScriptAssembly(compiledAssemblyName, syntaxTree, externalMetadataReferences,
compilationOptions, out messages, externFileAssemblyRefs);
}
catch (Exception e)
{
ModUtils.Logging.PrintError($"{nameof(AssemblyManager)}::{nameof(LoadAssemblyFromMemory)}() | Failed to compile and load assemblies for [ {compiledAssemblyName} / {friendlyName} ]! Details: {e.Message}");
return AssemblyLoadingSuccessState.InvalidAssembly;
}
// get types // get types
if (state is AssemblyLoadingSuccessState.Success) if (state is AssemblyLoadingSuccessState.Success)
@@ -654,7 +678,15 @@ public class AssemblyManager
OpsLockUnloaded.EnterWriteLock(); OpsLockUnloaded.EnterWriteLock();
try try
{ {
if (id.Equals(Guid.Empty) || !LoadedACLs.ContainsKey(id) || LoadedACLs[id] is null) if (LoadedACLs.ContainsKey(id) && LoadedACLs[id] == null)
{
if (!LoadedACLs.TryRemove(id, out _))
{
ModUtils.Logging.PrintWarning($"An ACL with the GUID {id.ToString()} was found as null. Unable to remove null ACL entry.");
}
}
if (id.Equals(Guid.Empty) || !LoadedACLs.ContainsKey(id))
{ {
return false; // nothing to dispose of return false; // nothing to dispose of
} }
@@ -143,7 +143,7 @@ public class MemoryFileAssemblyContextLoader : AssemblyLoadContext
} }
var externAssemblyRefs = externFileAssemblyReferences is not null ? externFileAssemblyReferences.ToImmutableList() : ImmutableList<Assembly>.Empty; var externAssemblyRefs = externFileAssemblyReferences is not null ? externFileAssemblyReferences.ToImmutableList() : ImmutableList<Assembly>.Empty;
var externAssemblyNames = externAssemblyRefs.Any() ? externAssemblyRefs var externAssemblyNames = !externAssemblyRefs.IsEmpty ? externAssemblyRefs
.Where(a => a.FullName is not null) .Where(a => a.FullName is not null)
.Select(a => a.FullName).ToImmutableHashSet() .Select(a => a.FullName).ToImmutableHashSet()
: ImmutableHashSet<string>.Empty; : ImmutableHashSet<string>.Empty;
@@ -178,33 +178,37 @@ public class MemoryFileAssemblyContextLoader : AssemblyLoadContext
.Select(a => MetadataReference.CreateFromFile(a.Location) as MetadataReference) .Select(a => MetadataReference.CreateFromFile(a.Location) as MetadataReference)
).ToList()); ).ToList());
// build metadata refs from ACL assemblies from files/disk. ImmutableList<AssemblyManager.LoadedACL> loadedAcls = _assemblyManager.GetAllLoadedACLs().ToImmutableList();
foreach (AssemblyManager.LoadedACL loadedAcl in _assemblyManager.GetAllLoadedACLs()) if (!loadedAcls.IsEmpty)
{ {
if(loadedAcl.Acl.IsTemplateMode || loadedAcl.Acl.IsDisposed) // build metadata refs from ACL assemblies from files/disk.
continue; foreach (AssemblyManager.LoadedACL loadedAcl in loadedAcls)
metadataReferences.AddRange(loadedAcl.Acl.Assemblies {
.Where(a => if(loadedAcl?.Acl is null || loadedAcl.Acl.IsTemplateMode || loadedAcl.Acl.IsDisposed)
{ continue;
if (a.IsDynamic || string.IsNullOrWhiteSpace(a.Location) || a.Location.Contains("xunit")) metadataReferences.AddRange(loadedAcl.Acl.Assemblies
return false; .Where(a =>
if (a.FullName is null) {
return true; if (a.IsDynamic || string.IsNullOrWhiteSpace(a.Location) || a.Location.Contains("xunit"))
return !externAssemblyNames.Contains(a.FullName); // exclude duplicates return false;
}) if (a.FullName is null)
.Select(a => MetadataReference.CreateFromFile(a.Location) as MetadataReference) return true;
.Union(externAssemblyRefs // add custom supplied assemblies return !externAssemblyNames.Contains(a.FullName); // exclude duplicates
.Where(a => !(a.IsDynamic || string.IsNullOrEmpty(a.Location) || a.Location.Contains("xunit"))) })
.Select(a => MetadataReference.CreateFromFile(a.Location) as MetadataReference) .Select(a => MetadataReference.CreateFromFile(a.Location) as MetadataReference)
).ToList()); .Union(externAssemblyRefs // add custom supplied assemblies
} .Where(a => !(a.IsDynamic || string.IsNullOrEmpty(a.Location) || a.Location.Contains("xunit")))
.Select(a => MetadataReference.CreateFromFile(a.Location) as MetadataReference)
).ToList());
}
// build metadata refs from in-memory images // build metadata refs from in-memory images
foreach (var loadedAcl in _assemblyManager.GetAllLoadedACLs()) foreach (var loadedAcl in loadedAcls)
{ {
if (loadedAcl.Acl.CompiledAssemblyImage is null || loadedAcl.Acl.CompiledAssemblyImage.Length == 0) if (loadedAcl.Acl.CompiledAssemblyImage is null || loadedAcl.Acl.CompiledAssemblyImage.Length == 0)
continue; continue;
metadataReferences.Add(MetadataReference.CreateFromImage(loadedAcl.Acl.CompiledAssemblyImage)); metadataReferences.Add(MetadataReference.CreateFromImage(loadedAcl.Acl.CompiledAssemblyImage));
}
} }
// Change inaccessible options to allow public access to restricted members // Change inaccessible options to allow public access to restricted members