Skip to content

Commit

Permalink
[release/6.0] [mono] Use unsigned char when computing UTF8 string has…
Browse files Browse the repository at this point in the history
…hes (#83303)

* [mono] Use `unsigned char` when computing UTF8 string hashes

The C standard does not specify whether `char` is signed or unsigned,
it is implementation defined.

Apparently Android aarch64 makes a different choice than other
platforms (at least macOS arm64 and Windows x64 give different
results).

Mono uses `mono_metadata_str_hash` in the AOT compiler and AOT runtime
to optimize class name lookup.  As a result, classes whose names
include UTF-8 continuation bytes (with the high bit = 1) will hash
differently in the AOT compiler and on the device.

Fixes #82187
Fixes #78638

* Add regression test

---------

Co-authored-by: Aleksey Kliger <alklig@microsoft.com>
  • Loading branch information
github-actions[bot] and lambdageek authored Mar 30, 2023
1 parent fc32833 commit 0254cce
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/mono/mono/eglib/ghashtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ guint
g_str_hash (gconstpointer v1)
{
guint hash = 0;
char *p = (char *) v1;
unsigned char *p = (unsigned char *) v1;

while (*p++)
hash = (hash << 5) - (hash + *p);
Expand Down
3 changes: 2 additions & 1 deletion src/mono/mono/metadata/metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -5386,7 +5386,8 @@ guint
mono_metadata_str_hash (gconstpointer v1)
{
/* Same as g_str_hash () in glib */
char *p = (char *) v1;
/* note: signed/unsigned char matters - we feed UTF-8 to this function, so the high bit will give diferent results if we don't match. */
unsigned char *p = (unsigned char *) v1;
guint hash = *p;

while (*p++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<Compile Include="repro.cs" />
</ItemGroup>
</Project>
31 changes: 31 additions & 0 deletions src/tests/Loader/classloader/regressions/GitHub_82187/repro.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;

/* Regression test for https://github.com/dotnet/runtime/issues/78638
* and https://github.com/dotnet/runtime/issues/82187 ensure AOT
* cross-compiler and AOT runtime use the same name hashing for names
* that include UTF-8 continuation bytes.
*/

[MySpecial(typeof(MeineTüre))]
public class Program
{
public static int Main()
{
var attr = (MySpecialAttribute)Attribute.GetCustomAttribute(typeof (Program), typeof(MySpecialAttribute), false);
if (attr == null)
return 101;
if (attr.Type == null)
return 102;
if (attr.Type.FullName != "MeineTüre")
return 103;
return 100;
}
}

public class MySpecialAttribute : Attribute
{
public Type Type {get; private set; }
public MySpecialAttribute(Type t) { Type = t; }
}

public class MeineTüre {}

0 comments on commit 0254cce

Please sign in to comment.