Custom Attribute blob syntax for System.Type is unclear
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
Research direction
Start with ECMA-335 § II.23.3 and CoreCLR's TypeNameResolver.CoreCLR.cs, especially the fallback behavior linked in the issue. Compare that behavior with Roslyn, Cecil, and dnLib, then establish an agreed resolution rule for omitted assembly names; done requires a decided approach and corresponding runtime coverage.
Written by the indexing model from the issue text.
Description
Specifically:
ECMA-335 § II.23.3
- If the parameter kind is System.Type, (also, the middle line in above diagram) its is stored as a SerString (as defined in the previous paragraph), representing its name. The canonical name is its full type name, followed optionally by assembly where it is defined, its version, culture and public-key-token. If the name is omitted, the CLI looks first in the current assembly, and then in the system library (mscorlib); in these two special cases, it is permitted to omit the name, version, culture and public-key-token.
(emphasis mine)
The spec calls out mscorlib here, which was reasonable for .NET Framework. However, in .NET Core and .NET Standard, the corelib is no longer in mscorlib, but rather (in the API contract) System.Runtime or netstandard primarily. CoreCLR does not use any of these, however, and instead uses System.Private.CoreLib as the fallback, despite that being a (supposedly) private implementation detail. This is most notably a problem for System.Uri: it is in the reference corelib (System.Uri) on .NET Core and .NET Standard, but its implementation is in System.Private.Uri, not System.Private.CoreLib, so a CA blob that contains System.Uri will fail to resolve!
More detail on where this was found:
https://github.com/Washi1337/AsmResolver/pull/648
@Windows10CE:
For some additional references for behavior being changed by this PR, all checked 2025-06-12:
ECMA-335 6th Edition, Section II.23.3, bottom of page 268, describes how to do resolution when no assembly spec is given for Type arguments: https://ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf
The current behavior of CoreCLR, which attempts current assembly, then
typeof(object).Assembly(System.Private.CoreLib), then the TypeResolve event of the current AssemblyLoadContext: https://github.com/dotnet/runtime/blob/b49ebac33e06556804af96afebbb8f706d51a2e2/src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.CoreCLR.cs#L344The current behavior of Roslyn (the C#/VB compiler), which always writes FQNs when there is an assembly being referenced: https://github.com/dotnet/roslyn/blob/2f32bf87e211fe5319c94f442c4ad56254bc75e0/src/Compilers/Core/Portable/PEWriter/TypeNameSerializer.cs#L194
Cecil reading always uses
module.TypeSystem.CoreLibrarywhen it cannot find a type definition (the current behavior of AsmResolver): https://github.com/jbevain/cecil/blob/3136847ea620fb9b4a3ff96bc4f573148e8bd2e4/Mono.Cecil/TypeParser.cs#L356Cecil writing follows the ECMA section to the letter and only omits it when the assembly being referenced is exactly current module or mscorlib (this behavior is absolutely incorrect and almost certainly has real issues, I just cannot be bothered to synthesize examples of it, this fails when referencing mscorlib for any type that is not today in System.Private.CoreLib and then loading that attribute with CoreCLR): https://github.com/jbevain/cecil/blob/3136847ea620fb9b4a3ff96bc4f573148e8bd2e4/Mono.Cecil/TypeParser.cs#L521
dnLib reading does the same behavior as current AsmResolver and Cecil, attempting current module, then the referenced corlib: https://github.com/0xd4d/dnlib/blob/c78d296c522aae0520df2afd825d48266321cf36/src/DotNet/CustomAttributeReader.cs#L24
dnLib writing has an option flag for whether to enable the same optimization that AsmResolver currently employs: https://github.com/0xd4d/dnlib/blob/c78d296c522aae0520df2afd825d48266321cf36/src/DotNet/Writer/Metadata.cs#L182-L196
Even Cecil is technically wrong here, with respect to what CoreCLR does! The only actually correct thing to do is what Roslyn does, but that poses a problem when trying to load potentially poorly authored assemblies, because there's not a good answer for what to do.
Proposed solution(s)
- Formally deprecate (e.g. in an ECMA augment) omitting the assembly for corelib types
- Make CoreCLR (and Mono, if necessary) resolve such types through the
mscorlibforwarder assembly (and maybe other forwarder assemblies depending on the source assembly's defined targetframework?)
- .NET Framework assemblies authored according to spec will load properly, though there is a risk that some incorrectly-authored .NET Standard or .NET Core assemblies will fail to resolve properly without checking the defined TargetFramework
Alternatively:
Augment ECMA to specify resolving-through
System.Runtimeinstead ofmscorlib, and adjust CoreCLR and Mono appropriately
- This sucks, because not specifying the assembly sucks in the first place.
A slightly more out-there idea is to rev the CA blob format and deprecate the string form entirely, replacing it with an encoded TypeDef/TypeRef/TypeSpec token and using all of the goodness of the .NET metadata format here, too.
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from dotnet/runtime
-
agentic-workflows untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
area-System.Reflection blocking-clean-ci-optional Known Build Error os-mac-os-x untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
area-CodeGen-coreclr untriaged
Difficulty 1/5 Under an hour Newbie friendliness 92/100
-
agentic-workflows untriaged
Difficulty 1/5 Under an hour Newbie friendliness 78/100
-
area-VM-meta-mono untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
:watch: Not Triaged 11.0 fundamentals/subsvc
Difficulty 2/5 1-3 hours Newbie friendliness 92/100
dotnet/AspNetCore.Docs#37699 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SubtitleEdit/subtitleedit#15108 · 1 comment ·
-
area/docs-content Bug pulumi/docs
Difficulty 1/5 1-3 hours Newbie friendliness 94/100
-
Create parent directories only after the containment check in InstallHelper.TryExtractToDirectory Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
PowerShell/PSResourceGet#2056 ·