Skip to content

System.Xml.Serialization.XmlSerializer: A non-collectible assembly may not reference a collectible assembly #100519

Open
@cvium

Description

@cvium

Description

#58932 did not properly fix the issues with collectible load contexts. When trying to serialize a generic collection containing the type from a collectible load context (e.g. System.Collections.Generic.List``1[Module.Bar]), the assembly from Type.Assembly is System.Private.CoreLib, which is not collectible, it therefore creates a hard ref to the type and crashes.

Is there a specific reason that the check is on the type's assembly (https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ContextAwareTables.cs#L35)? It seems that Type has a property called IsCollectible, which should be preferred or am I missing something?

I have forked the original sample project and modified it (simply changing it to new XmlSerializer(typeof(List<Bar>))): https://github.com/cvium/AssemblyLoadContextBug

Reproduction Steps

https://github.com/cvium/AssemblyLoadContextBug

  1. dotnet build Module
  2. dotnet build CrashSample
  3. cd CrashSample
  4. dotnet bin/Debug/net8.0/CrashSample.dll

Expected behavior

It serializes the type correctly.

Actual behavior

It crashes with this stacktrace

Unhandled exception. System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.NotSupportedException: A non-collectible assembly may not reference a collectible assembly.
   at System.Reflection.Emit.RuntimeModuleBuilder.GetTypeRefNested(Type type, Module refedModule)
   at System.Reflection.Emit.RuntimeModuleBuilder.GetTypeTokenWorkerNoLock(Type type, Boolean getGenericDefinition)
   at System.Reflection.Emit.RuntimeModuleBuilder.GetTypeTokenInternal(Type type, Boolean getGenericDefinition)
   at System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(Type clsArgument, Boolean lastWasGenericInst)
   at System.Reflection.Emit.SignatureHelper.AddOneArgTypeHelperWorker(Type clsArgument, Boolean lastWasGenericInst)
   at System.Reflection.Emit.RuntimeILGenerator.DeclareLocal(Type localType, Boolean pinned)
   at System.Xml.Serialization.CodeGenerator.DeclareLocal(Type type, String name)
   at System.Xml.Serialization.CodeGenerator.DeclareOrGetLocal(Type type, String name)
   at System.Xml.Serialization.ReflectionAwareILGen.WriteArrayLocalDecl(String typeName, String variableName, SourceInfo initValue, TypeDesc arrayTypeDesc)
   at System.Xml.Serialization.XmlSerializationWriterILGen.WriteElement(SourceInfo source, ElementAccessor element, String arrayName, Boolean writeAccessor)
   at System.Xml.Serialization.XmlSerializationWriterILGen.WriteElements(SourceInfo source, String enumSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, String arrayName, Boolean writeAccessors, Boolean isNullable)
   at System.Xml.Serialization.XmlSerializationWriterILGen.WriteMember(SourceInfo source, String choiceSource, ElementAccessor[] elements, TextAccessor text, ChoiceIdentifierAccessor choice, TypeDesc memberTypeDesc, Boolean writeAccessors)
   at System.Xml.Serialization.XmlSerializationWriterILGen.GenerateTypeElement(XmlTypeMapping xmlTypeMapping)
   at System.Xml.Serialization.TempAssembly.GenerateRefEmitAssembly(XmlMapping[] xmlMappings, Type[] types)
   at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location)
   at System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace, String location)
   at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
   at Module.Foo..ctor()
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)
   --- End of inner exception stack trace ---
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)
   at CrashSample.Program.ExecuteAssembly() in C:\Users\name\RiderProjects\AssemblyLoadContextBug\CrashSample\Program.cs:line 30
   at CrashSample.Program.Main(String[] args) in C:\Users\name\RiderProjects\AssemblyLoadContextBug\CrashSample\Program.cs:line 13

Regression?

No response

Known Workarounds

Possible workarounds:

  • Wrap the coreclr collection types in a class that originates from a collectible load context thereby forcing the Type.Assembly ALC to be "correct"
  • Use DataContractSerializer

Configuration

Running this on Windows 10 x64 using dotnet 8.0.103.

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions