Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mono is unable to find assemblies named with some international characters #103276

Closed
rolfbjarne opened this issue Jun 11, 2024 · 4 comments · Fixed by #103363
Closed

Mono is unable to find assemblies named with some international characters #103276

rolfbjarne opened this issue Jun 11, 2024 · 4 comments · Fixed by #103363
Assignees
Milestone

Comments

@rolfbjarne
Copy link
Member

rolfbjarne commented Jun 11, 2024

Description

Type.GetType fails if using fully qualified assembly names where the assembly has certain international characters.

Reproduction Steps

Test case: testcase-3df4585.zip

Execute this to see failure:

$ rm -rf bin obj
$ dotnet build /p:AssemblyName=工程
$ bin/Debug/net8.0-maccatalyst/maccatalyst-*/工程.app/Contents/MacOS/工程

The test code is doing this:

var aqn = GetType ().AssemblyQualifiedName!;
var t = Type.GetType (aqn);
if (t is null) {
	Console.WriteLine ($"❌ FAILED could not find the type '{aqn}'");
} else {
	Console.WriteLine ($"✅ PASSED found {t.AssemblyQualifiedName}");
}

Expected behavior

✅ PASSED found testcase.AppDelegate, 工程, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

Actual behavior

❌ FAILED could not find the type 'testcase.AppDelegate, 工程, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'

Regression?

I don't think so.

Known Workarounds

Stick to ASCII...

Configuration

 $ dotnet --info
.NET SDK:
 Version:           8.0.301
 Commit:            1a0e9c0300
 Workload version:  8.0.300-manifests.3a2c5bc5
 MSBuild version:   17.10.4+10fbfbf2e

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  14.5
 OS Platform: Darwin
 RID:         osx-arm64
 Base Path:   /usr/local/share/dotnet/sdk/8.0.301/

.NET workloads installed:
 [maui-maccatalyst]
   Installation Source: SDK 8.0.300
   Manifest Version:    8.0.21/8.0.100
   Manifest Path:       /usr/local/share/dotnet/sdk-manifests/8.0.100/microsoft.net.sdk.maui/8.0.21/WorkloadManifest.json
   Install Type:        FileBased

 [ios]
   Installation Source: SDK 8.0.300
   Manifest Version:    17.2.8473-ci.main/8.0.100
   Manifest Path:       /usr/local/share/dotnet/sdk-manifests/8.0.100/microsoft.net.sdk.ios/17.2.8473-ci.main/WorkloadManifest.json
   Install Type:        FileBased

 [maccatalyst]
   Installation Source: SDK 8.0.300
   Manifest Version:    17.2.8473-ci.main/8.0.100
   Manifest Path:       /usr/local/share/dotnet/sdk-manifests/8.0.100/microsoft.net.sdk.maccatalyst/17.2.8473-ci.main/WorkloadManifest.json
   Install Type:        FileBased


Host:
  Version:      9.0.0-preview.4.24266.19
  Architecture: arm64
  Commit:       d0d6fed6c0

.NET SDKs installed:
  7.0.311 [/usr/local/share/dotnet/sdk]
  8.0.100 [/usr/local/share/dotnet/sdk]
  8.0.104 [/usr/local/share/dotnet/sdk]
  8.0.201 [/usr/local/share/dotnet/sdk]
  8.0.301 [/usr/local/share/dotnet/sdk]
  9.0.100-preview.3.24153.2 [/usr/local/share/dotnet/sdk]
  9.0.100-preview.4.24260.3 [/usr/local/share/dotnet/sdk]
  9.0.100-preview.4.24267.66 [/usr/local/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 7.0.14 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.2 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.6 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 9.0.0-preview.3.24151.1 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 9.0.0-preview.4.24260.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 9.0.0-preview.4.24267.6 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 7.0.14 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.2 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.6 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 9.0.0-preview.3.24129.2 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 9.0.0-preview.4.24260.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 9.0.0-preview.4.24266.19 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  Not set

global.json file:
  /Users/rolf/test/dotnet/2034162/testcase/global.json

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

Other information

Using a different assembly name works fine:

$ rm -rf bin obj
$ dotnet build /p:AssemblyName=ThisWorks
$ bin/Debug/net8.0-maccatalyst/maccatalyst-*/ThisWorks.app/Contents/MacOS/ThisWorks
✅ PASSED found testcase.AppDelegate, ThisWorks, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

The problem seems to be in assembly_name_to_aname:

Breakpoint 1: where = 工程`assembly_name_to_aname + 17 at reflection.c:1520:2, address = 0x0000000100275a61
(lldb) c
Process 5583 resuming
Process 5583 stopped
* thread #1, name = 'tid_103', queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100275a61 工程`assembly_name_to_aname(assembly=0x000000030476b1a0, p="工程, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null") at reflection.c:1520:2 [opt]
Target 0: (工程) stopped.
(lldb) finish
Process 5583 stopped
* thread #1, name = 'tid_103', queue = 'com.apple.main-thread', stop reason = step out
Return value: (int) $0 = 1

    frame #0: 0x00000001002741e0 工程`_mono_reflection_parse_type(name=<unavailable>, endptr=0x0000000000000000, is_recursed=0, info=0x000000030476b190) at reflection.c:1847:9 [opt]
Target 0: (工程) stopped.
(lldb) p *(MonoAssemblyName *) 0x000000030476b1a0
(MonoAssemblyName) {
  name = 0x00006000001a5336 "工程, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
  culture = 0x00000001003e7608 ""
  hash_value = 0x0000000000000000
  public_key = 0x0000000000000000
  public_key_token = ""
  hash_alg = 0
  hash_len = 0
  flags = 0
  major = 0
  minor = 0
  build = 0
  revision = 0
  arch = 0
  without_version = '\x01'
  without_culture = '\x01'
  without_public_key_token = '\x01'
}

I believe the returned MonoAssemblyName should be:

(MonoAssemblyName) {
  name = 0x00006000001a5336 "工程"
  culture = 0x00000001003e7608 ""
  hash_value = 0x0000000000000000
  public_key = 0x0000000000000000
  public_key_token = ""
  hash_alg = 0
  hash_len = 0
  flags = 0
  major = 1
  minor = 0
  build = 0
  revision = 0
  arch = 0
  without_version = '\0'
  without_culture = '\0'
  without_public_key_token = '\0'
}
@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Jun 11, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Jun 11, 2024
@rolfbjarne
Copy link
Member Author

CC @steveisok

@filipnavara filipnavara added area-VM-meta-mono and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Jun 11, 2024
@lambdageek
Copy link
Member

Yea it's just not properly dealing with non-ASCII UTF8:

	while (*p && (isalnum (*p) || *p == '.' || *p == '-' || *p == '_' || *p == '$' || *p == '@' || g_ascii_isspace (*p)))
		p++;
	if (quoted) {
		if (*p != '"')
			return 1;
		*p = 0;
		p++;
	}
	g_strchomp (s);
	assembly->name = s;
	if (*p != ',') {
		g_strchomp (s);
		assembly->name = s;
		return 1;
	}

*p initially points to which is {0xE5, 0xB7, 0xA5} so isalnum is false and the while loop is skipped. we end up in the *p != ',' branch and bail out early.

This function should at least check for the high bit and then go down a slow path that uses unicode-aware parsing. (Or possibly this isalnum check can just be removed - the initial loop should just look for a recognizable delimiter, it probably doesn't matter what other characters we see along the way)

@jkotas
Copy link
Member

jkotas commented Jun 11, 2024

#45033 tracks switching Mono to shared type name parser. It would fix this and number of other bugs in the Mono type name parser (see tests disabled against 45033).

@lambdageek lambdageek removed the untriaged New issue has not been triaged by the area owner label Jun 11, 2024
@fanyang-mono fanyang-mono self-assigned this Jun 11, 2024
@steveisok steveisok added this to the 9.0.0 milestone Jun 11, 2024
@steveisok
Copy link
Member

@fanyang-mono we'll need to backport this to 8 once you have a fix as well.

steveisok pushed a commit that referenced this issue Jun 14, 2024
…#103363)

Fixes #103276

Added an automated test that the testcase failed in the above issue. It now passes with this change.

Ideally, Mono should share the same assembly name parsing logic as CoreCLR, which is `AssemblyNameParser.TryParse`.
@github-actions github-actions bot locked and limited conversation to collaborators Jul 14, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants