[runtime] Store assemblies' MVID in the generated static registrar code. (#15795)

This will increase app size a little bit: the space for the MVID + 4 bytes for each
assembly, but we'll be able to validate and show a helpful error message if the generated
static registrar code does not match the assembly loaded at runtime.

It's also a step toward per-assembly static registration (ref: #12067).
This commit is contained in:
Rolf Bjarne Kvinge 2022-09-08 10:34:05 +02:00 коммит произвёл GitHub
Родитель 9a52a6fbe7
Коммит aa8ded8e51
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
21 изменённых файлов: 361 добавлений и 43 удалений

Просмотреть файл

@ -56,8 +56,8 @@ typedef struct {
} MTProperty;
// This structure completely describes everything required to resolve a metadata token
typedef struct MTFullTokenReference {
const char *assembly_name; /* the name of the assembly */
typedef struct __attribute__((packed)) {
uint32_t assembly_index; /* index into the 'assemblies' array in the registration map */
uint32_t module_token;
uint32_t token;
} MTFullTokenReference;
@ -99,10 +99,15 @@ typedef struct __attribute__((packed)) {
const __unsafe_unretained Protocol * const * protocols; // the corresponding native protocols
} MTProtocolMap;
typedef struct __attribute__((packed)) {
const char *name;
const char *mvid;
} MTAssembly;
struct MTRegistrationMap;
struct MTRegistrationMap {
const char **assembly;
const MTAssembly *assemblies;
MTClassMap *map;
const MTFullTokenReference *full_token_references;
// There are some managed types that are not registered because their ObjC

Просмотреть файл

@ -10,6 +10,7 @@
#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.InteropServices;
@ -19,6 +20,10 @@ using Foundation;
using Registrar;
#endif
#if !COREBUILD
using Xamarin.Bundler;
#endif
#if !NET
using NativeHandle = System.IntPtr;
#endif
@ -56,8 +61,8 @@ namespace ObjCRuntime {
for (int i = 0; i < map->assembly_count; i++) {
var ptr = Marshal.ReadIntPtr (map->assembly, i * IntPtr.Size);
Runtime.Registrar.SetAssemblyRegistered (Marshal.PtrToStringAuto (ptr));
var assembly = map->assemblies [i];
Runtime.Registrar.SetAssemblyRegistered (Marshal.PtrToStringAuto (assembly.name));
}
}
@ -292,27 +297,27 @@ namespace ObjCRuntime {
if ((token_reference & 0x1) == 0x1) {
// full token reference
var idx = (int) (token_reference >> 1);
var entry = map->full_token_references + (IntPtr.Size + 8) * idx;
var entry = map->full_token_references [idx];
// first compare what's most likely to fail (the type's metadata token)
var token = (uint) Marshal.ReadInt32 (entry + IntPtr.Size + 4);
var token = entry.token;
type_token |= 0x02000000 /* TypeDef - the token type is explicit in the full token reference, but not present in the type_token argument, so we have to add it before comparing */;
if (type_token != token)
return false;
// then the module token
var module_token = (uint) Marshal.ReadInt32 (entry + IntPtr.Size);
var module_token = entry.module_token;
if (mod_token != module_token)
return false;
// leave the assembly name for the end, since it's the most expensive comparison (string comparison)
assembly_name = Marshal.ReadIntPtr (entry);
assembly_name = map->assemblies [entry.assembly_index].name;
} else {
// packed token reference
if (token_reference >> 8 != type_token)
return false;
var assembly_index = (token_reference >> 1) & 0x7F;
assembly_name = Marshal.ReadIntPtr (map->assembly, (int) assembly_index * IntPtr.Size);
assembly_name = map->assemblies [(int) assembly_index].name;
}
return Runtime.StringEquals (assembly_name, asm_name);
@ -380,10 +385,11 @@ namespace ObjCRuntime {
internal unsafe static MemberInfo? ResolveFullTokenReference (uint token_reference)
{
// sizeof (MTFullTokenReference) = IntPtr.Size + 4 + 4
var entry = Runtime.options->RegistrationMap->full_token_references + (IntPtr.Size + 8) * (int) (token_reference >> 1);
var assembly_name = Marshal.ReadIntPtr (entry);
var module_token = (uint) Marshal.ReadInt32 (entry + IntPtr.Size);
var token = (uint) Marshal.ReadInt32 (entry + IntPtr.Size + 4);
var idx = (int) (token_reference >> 1);
var entry = Runtime.options->RegistrationMap->full_token_references [idx];
var assembly_name = Runtime.options->RegistrationMap->assemblies [entry.assembly_index].name;
var module_token = entry.module_token;
var token = entry.token;
#if LOG_TYPELOAD
Console.WriteLine ($"ResolveFullTokenReference (0x{token_reference:X}) assembly name: {assembly_name} module token: 0x{module_token:X} token: 0x{token:X}.");
@ -430,7 +436,7 @@ namespace ObjCRuntime {
Console.WriteLine ($"ResolveTokenReference (0x{token_reference:X}) assembly index: {assembly_index} token: 0x{token:X}.");
#endif
var assembly_name = Marshal.ReadIntPtr (map->assembly, (int) assembly_index * IntPtr.Size);
var assembly_name = map->assemblies [(int) assembly_index].name;
var assembly = ResolveAssembly (assembly_name);
var module = ResolveModule (assembly, 0x1);
@ -474,7 +480,65 @@ namespace ObjCRuntime {
throw ErrorHelper.CreateError (8020, $"Could not find the module with MetadataToken 0x{token:X} in the assembly {assembly}.");
}
// Restrict this code to desktop for now, which is where most of the problems with outdated generated static registrar code occur.
#if __MACOS__ || __MACCATALYST__
static bool? verify_static_registrar_code;
static object? verification_lock;
static Dictionary<IntPtr, object?>? verified_assemblies; // Use Dictionary instead of HashSet to avoid pulling in System.Core.dll.
unsafe static void VerifyStaticRegistrarCode (IntPtr assembly_name, Assembly assembly)
{
if (verify_static_registrar_code is null) {
verify_static_registrar_code = !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("XAMARIN_VALIDATE_STATIC_REGISTRAR_CODE"));
verification_lock = new object ();
}
if (verify_static_registrar_code != true)
return;
lock (verification_lock!) {
if (verified_assemblies is null) {
verified_assemblies = new Dictionary<IntPtr, object?> (Runtime.IntPtrEqualityComparer);
} else if (verified_assemblies.ContainsKey (assembly_name)) {
return;
}
verified_assemblies [assembly_name] = null;
}
var map = Runtime.options->RegistrationMap;
if (map is null)
return;
for (var i = 0; i < map->assembly_count; i++) {
var entry = map->assemblies [i];
var name = Marshal.PtrToStringAuto (entry.name)!;
if (!Runtime.StringEquals (assembly_name, name))
continue;
try {
var mvid = Marshal.PtrToStringAuto (entry.mvid)!;
var runtime_mvid = assembly.ManifestModule.ModuleVersionId;
var registered_mvid = Guid.Parse (mvid);
if (registered_mvid == runtime_mvid)
continue;
throw ErrorHelper.CreateError (8044, Errors.MX8044 /* The assembly {0} has been modified since the app was built, invalidating the generated static registrar code. The MVID for the loaded assembly is {1}, while the MVID for the assembly the generated static registrar code corresponds to is {2}. */, name, runtime_mvid, registered_mvid);
} catch (Exception e) {
throw ErrorHelper.CreateError (8043, e, Errors.MX8043 /* An exception occurred while validating the static registrar code for {0}: {1} */, name, e.Message);
}
}
}
#endif // __MACOS__ || __MACCATALYST__
static Assembly ResolveAssembly (IntPtr assembly_name)
{
if (TryResolveAssembly (assembly_name, out var asm)) {
#if __MACOS__ || __MACCATALYST__
VerifyStaticRegistrarCode (assembly_name, asm);
#endif
return asm;
}
throw ErrorHelper.CreateError (8019, $"Could not find the assembly {Marshal.PtrToStringAuto (assembly_name)} in the loaded assemblies.");
}
static bool TryResolveAssembly (IntPtr assembly_name, [NotNullWhen (true)] out Assembly? assembly)
{
// Find the assembly. We've already loaded all the assemblies that contain registered types, so just look at those assemblies.
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies ()) {
@ -482,12 +546,14 @@ namespace ObjCRuntime {
continue;
#if LOG_TYPELOAD
Console.WriteLine ($"ResolveAssembly (0x{assembly_name:X}): {asm.FullName}.");
Console.WriteLine ($"TryResolveAssembly (0x{assembly_name:X}): {asm.FullName}.");
#endif
return asm;
assembly = asm;
return true;
}
throw ErrorHelper.CreateError (8019, $"Could not find the assembly {Marshal.PtrToStringAuto (assembly_name)} in the loaded assemblies.");
assembly = null;
return false;
}
internal unsafe static uint GetTokenReference (Type type, bool throw_exception = true)
@ -514,7 +580,7 @@ namespace ObjCRuntime {
// Find the assembly index in our list of registered assemblies.
int assembly_index = -1;
for (int i = 0; i < map->assembly_count; i++) {
var name_ptr = Marshal.ReadIntPtr (map->assembly, (int) i * IntPtr.Size);
var name_ptr = map->assemblies [(int) i].name;
if (Runtime.StringEquals (name_ptr, asm_name)) {
assembly_index = i;
break;
@ -542,15 +608,16 @@ namespace ObjCRuntime {
{
var map = Runtime.options->RegistrationMap;
for (int i = 0; i < map->full_token_reference_count; i++) {
var ptr = map->full_token_references + (i * (IntPtr.Size + 8));
var asm_ptr = Marshal.ReadIntPtr (ptr);
var token = Marshal.ReadInt32 (ptr + IntPtr.Size + 4);
var ftr = map->full_token_references [i];
var token = ftr.token;
if (token != metadata_token)
continue;
var mod_token = Marshal.ReadInt32 (ptr + IntPtr.Size);
var mod_token = ftr.module_token;
if (mod_token != module_token)
continue;
if (!Runtime.StringEquals (asm_ptr, assembly_name))
var assembly_index = ftr.assembly_index;
var assembly = map->assemblies [assembly_index];
if (!Runtime.StringEquals (assembly.name, assembly_name))
continue;
return ((uint) i << 1) + 1;

Просмотреть файл

@ -55,9 +55,9 @@ namespace ObjCRuntime {
#pragma warning disable 649 // Field 'X' is never assigned to, and will always have its default value
internal unsafe struct MTRegistrationMap {
public IntPtr assembly;
public MTAssembly *assemblies;
public MTClassMap *map;
public IntPtr full_token_references; /* array of MTFullTokenReference */
public MTFullTokenReference *full_token_references;
public MTManagedClassMap* skipped_map;
public MTProtocolWrapperMap* protocol_wrapper_map;
public MTProtocolMap protocol_map;
@ -78,6 +78,13 @@ namespace ObjCRuntime {
UserType = 2,
}
[StructLayout (LayoutKind.Sequential, Pack = 1)]
internal unsafe struct MTFullTokenReference {
public uint assembly_index;
public uint module_token;
public uint token;
}
[StructLayout (LayoutKind.Sequential, Pack = 1)]
internal struct MTClassMap {
public IntPtr handle;
@ -104,6 +111,12 @@ namespace ObjCRuntime {
public IntPtr* protocols;
}
[StructLayout (LayoutKind.Sequential, Pack = 1)]
internal unsafe struct MTAssembly {
public IntPtr name;
public IntPtr mvid;
}
/* Keep Delegates, Trampolines and InitializationOptions in sync with monotouch-glue.m */
#pragma warning disable 649 // Field 'X' is never assigned to, and will always have its default value
internal struct Trampolines {

Просмотреть файл

@ -0,0 +1,63 @@
using System;
using System.Runtime.InteropServices;
using Foundation;
using ObjCRuntime;
namespace MySimpleApp
{
public class Program
{
static int Main (string[] args)
{
Console.WriteLine (Environment.GetEnvironmentVariable ("MAGIC_WORD"));
#if INCLUDED_ADDITIONAL_CODE
GC.KeepAlive (typeof (AdditionalClass));
#endif
return StaticRegistrarValidationTest ();
}
static int StaticRegistrarValidationTest ()
{
try {
using var obj = new SomeObj ();
obj.Whatever ();
xamarin_IntPtr_objc_msgSend_IntPtr_ref_IntPtr_exception (obj.Handle, Selector.GetHandle ("whatever"), IntPtr.Zero, IntPtr.Zero, out var gchandle);
Console.WriteLine ($"GCH: {gchandle}");
if (gchandle != IntPtr.Zero) {
var gch = GCHandle.FromIntPtr (gchandle);
var exc = (Exception) gch.Target;
gch.Free ();
throw exc;
}
return 1; // We're not supposed to get here
} catch (Exception e) {
Console.WriteLine ($"E: {e}");
if (e.Message.Contains ("The assembly MyRegistrarApp has been modified since the app was built, invalidating the generated static registrar code."))
return 0;
return 2;
}
}
[DllImport ("__Internal")]
static extern IntPtr xamarin_IntPtr_objc_msgSend_IntPtr_ref_IntPtr_exception (IntPtr handle, IntPtr selector, IntPtr p0, IntPtr p1, out IntPtr gchandle);
}
public class SomeObj : NSObject
{
[Export ("whatever")]
public IntPtr Whatever ()
{
return new IntPtr (0xdeadf00d);
}
}
public class DeadClass {} // Some code for the linker to remove
#if INCLUDED_ADDITIONAL_CODE
public class AdditionalClass {
}
#endif
}

Просмотреть файл

@ -0,0 +1 @@
include ../shared.mk

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-maccatalyst</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

Просмотреть файл

@ -0,0 +1,2 @@
TOP=../../..
include $(TOP)/tests/common/shared-dotnet-test.mk

Просмотреть файл

@ -0,0 +1 @@
include ../shared.mk

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-ios</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

Просмотреть файл

@ -0,0 +1 @@
include ../shared.mk

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-macos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

Просмотреть файл

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<OutputType>Exe</OutputType>
<ApplicationTitle>MyRegistrarApp</ApplicationTitle>
<ApplicationId>com.xamarin.myregistrarapp</ApplicationId>
<ExcludeNUnitLiteReference>true</ExcludeNUnitLiteReference>
<ExcludeTouchUnitReference>true</ExcludeTouchUnitReference>
<DefineConstants>$(DefineConstants);$(AdditionalDefineConstants)</DefineConstants>
</PropertyGroup>
<Import Project="../../common/shared-dotnet.csproj" />
<ItemGroup>
<Compile Include="../*.cs" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,3 @@
TOP=../../../..
TESTNAME=MyRegistrarApp
include $(TOP)/tests/common/shared-dotnet.mk

Просмотреть файл

@ -0,0 +1 @@
include ../shared.mk

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net$(BundledNETCoreAppTargetFrameworkVersion)-tvos</TargetFramework>
</PropertyGroup>
<Import Project="..\shared.csproj" />
</Project>

Просмотреть файл

@ -34,7 +34,7 @@ class MainClass {
// Capture the current time
var timestamp = DateTime.UtcNow;
File.WriteAllText (mainFile, mainContents + "\n");
File.WriteAllText (mainFile, mainContents);
// Build again
rv = DotNet.AssertBuild (project_path, properties);

Просмотреть файл

@ -0,0 +1,55 @@
namespace Xamarin.Tests {
[TestFixture]
public class RegistrarTest : TestBaseClass
{
[TestCase (ApplePlatform.MacCatalyst, true)]
[TestCase (ApplePlatform.MacOSX, true)]
[TestCase (ApplePlatform.iOS, false)]
[TestCase (ApplePlatform.TVOS, false)]
public void InvalidStaticRegistrarValidation (ApplePlatform platform, bool validated)
{
var project = "MyRegistrarApp";
var configuration = "Debug";
var runtimeIdentifiers = GetDefaultRuntimeIdentifier (platform);
Configuration.IgnoreIfIgnoredPlatform (platform);
var projectPath = GetProjectPath (project, platform: platform);
Clean (projectPath);
var properties = GetDefaultProperties ();
properties ["Registrar"] = "static";
// enable the linker (so that the main assembly is modified)
properties ["LinkMode"] = "full";
properties ["MtouchLink"] = "full";
DotNet.AssertBuild (projectPath, properties);
var appDir = GetAppPath (projectPath, platform, runtimeIdentifiers, configuration);
var asmDir = Path.Combine (appDir, GetRelativeAssemblyDirectory (platform));
var appExecutable = Path.Combine (asmDir, project + ".dll");
// Save the first version of the main assembly in memory
var firstAssembly = File.ReadAllBytes (appExecutable);
// Build again, including additional code
properties ["AdditionalDefineConstants"] = "INCLUDED_ADDITIONAL_CODE";
DotNet.AssertBuild (projectPath, properties);
// Revert to the original version of the main assembly
File.WriteAllBytes (appExecutable, firstAssembly);
Environment.SetEnvironmentVariable ("XAMARIN_VALIDATE_STATIC_REGISTRAR_CODE", "1");
try {
if (validated) {
ExecuteProjectWithMagicWordAndAssert (projectPath, platform, runtimeIdentifiers);
} else if (CanExecute (platform, runtimeIdentifiers)) {
var rv = base.Execute (GetNativeExecutable (platform, appDir), out var output, out _);
Assert.AreEqual (1, rv.ExitCode, "Expected no validation");
}
} finally {
Environment.SetEnvironmentVariable ("XAMARIN_VALIDATE_STATIC_REGISTRAR_CODE", null);
}
}
}
}

Просмотреть файл

@ -40,9 +40,24 @@ namespace Xamarin.Tests {
}
protected string GetAppPath (string projectPath, ApplePlatform platform, string runtimeIdentifiers, string configuration = "Debug")
{
return Path.Combine (GetBinDir (projectPath, platform, runtimeIdentifiers, configuration), Path.GetFileNameWithoutExtension (projectPath) + ".app");
}
protected string GetBinDir (string projectPath, ApplePlatform platform, string runtimeIdentifiers, string configuration = "Debug")
{
return GetBinOrObjDir ("bin", projectPath, platform, runtimeIdentifiers, configuration);
}
protected string GetObjDir (string projectPath, ApplePlatform platform, string runtimeIdentifiers, string configuration = "Debug")
{
return GetBinOrObjDir ("obj", projectPath, platform, runtimeIdentifiers, configuration);
}
protected string GetBinOrObjDir (string binOrObj, string projectPath, ApplePlatform platform, string runtimeIdentifiers, string configuration = "Debug")
{
var appPathRuntimeIdentifier = runtimeIdentifiers.IndexOf (';') >= 0 ? "" : runtimeIdentifiers;
return Path.Combine (Path.GetDirectoryName (projectPath)!, "bin", configuration, platform.ToFramework (), appPathRuntimeIdentifier, Path.GetFileNameWithoutExtension (projectPath) + ".app");
return Path.Combine (Path.GetDirectoryName (projectPath)!, binOrObj, configuration, platform.ToFramework (), appPathRuntimeIdentifier);
}
protected string GetOutputPath (string project, string? subdir, string runtimeIdentifiers, ApplePlatform platform, string configuration = "Debug")
@ -275,20 +290,25 @@ namespace Xamarin.Tests {
}
protected void ExecuteWithMagicWordAndAssert (string executable)
{
var rv = Execute (executable, out var output, out string magicWord);
Assert.That (output.ToString (), Does.Contain (magicWord), "Contains magic word");
Assert.AreEqual (0, rv.ExitCode, "ExitCode");
}
protected Execution Execute (string executable, out StringBuilder output, out string magicWord)
{
if (!File.Exists (executable))
throw new FileNotFoundException ($"The executable '{executable}' does not exists.");
var magicWord = Guid.NewGuid ().ToString ();
magicWord = Guid.NewGuid ().ToString ();
var env = new Dictionary<string, string?> {
{ "MAGIC_WORD", magicWord },
{ "DYLD_FALLBACK_LIBRARY_PATH", null }, // VSMac might set this, which may cause tests to crash.
};
var output = new StringBuilder ();
var rv = Execution.RunWithStringBuildersAsync (executable, Array.Empty<string> (), environment: env, standardOutput: output, standardError: output, timeout: TimeSpan.FromSeconds (15)).Result;
Assert.That (output.ToString (), Does.Contain (magicWord), "Contains magic word");
Assert.AreEqual (0, rv.ExitCode, "ExitCode");
output = new StringBuilder ();
return Execution.RunWithStringBuildersAsync (executable, Array.Empty<string> (), environment: env, standardOutput: output, standardError: output, timeout: TimeSpan.FromSeconds (15)).Result;
}
public static StringBuilder AssertExecute (string executable, params string[] arguments)

Просмотреть файл

@ -2118,7 +2118,7 @@ namespace Registrar {
AutoIndentStringBuilder full_token_references = new AutoIndentStringBuilder ();
uint full_token_reference_count;
List<string> registered_assemblies = new List<string> ();
List<(AssemblyDefinition Assembly, string Name)> registered_assemblies = new List<(AssemblyDefinition Assembly, string Name)> ();
bool IsPlatformType (TypeReference type)
{
@ -2837,9 +2837,9 @@ namespace Registrar {
if (string.IsNullOrEmpty (single_assembly)) {
foreach (var assembly in GetAssemblies ())
registered_assemblies.Add (GetAssemblyName (assembly));
registered_assemblies.Add (new (assembly, GetAssemblyName (assembly)));
} else {
registered_assemblies.Add (single_assembly);
registered_assemblies.Add (new (GetAssemblies ().Single (v => GetAssemblyName (v) == single_assembly), single_assembly));
}
foreach (var @class in allTypes) {
@ -3138,22 +3138,24 @@ namespace Registrar {
map.AppendLine ();
}
map.AppendLine ("static const char *__xamarin_registration_assemblies []= {");
map.AppendLine ("static const MTAssembly __xamarin_registration_assemblies [] = {");
int count = 0;
foreach (var assembly in registered_assemblies) {
count++;
if (count > 1)
map.AppendLine (", ");
map.Append ("\"");
map.Append (assembly);
map.Append ("\"");
map.Append ("{ \"");
map.Append (assembly.Name);
map.Append ("\", \"");
map.Append (assembly.Assembly.MainModule.Mvid.ToString ());
map.Append ("\" }");
}
map.AppendLine ();
map.AppendLine ("};");
map.AppendLine ();
if (full_token_reference_count > 0) {
map.AppendLine ("static const struct MTFullTokenReference __xamarin_token_references [] = {");
map.AppendLine ("static const MTFullTokenReference __xamarin_token_references [] = {");
map.AppendLine (full_token_references);
map.AppendLine ("};");
map.AppendLine ();
@ -4860,7 +4862,13 @@ namespace Registrar {
default:
throw ErrorHelper.CreateError (99, Errors.MX0099, $"unsupported tokentype ({member.MetadataToken.TokenType}) for {member.FullName}");
}
full_token_references.AppendFormat ("\t\t{{ /* #{3} = 0x{4:X} */ \"{0}\", 0x{1:X}, 0x{2:X} }},\n", GetAssemblyName (member.Module.Assembly), member.Module.MetadataToken.ToUInt32 (), member.MetadataToken.ToUInt32 (), full_token_reference_count, rv);
var assemblyIndex = registered_assemblies.FindIndex (v => v.Assembly == member.Module.Assembly);
var assemblyName = registered_assemblies [assemblyIndex].Name;
var moduleToken = member.Module.MetadataToken.ToUInt32 ();
var moduleName = member.Module.Name;
var memberToken = member.MetadataToken.ToUInt32 ();
var memberName = member.FullName;
full_token_references.Append ($"\t\t{{ /* #{full_token_reference_count} = 0x{rv:X} */ {assemblyIndex} /* {assemblyName} */, 0x{moduleToken:X} /* {moduleName} */, 0x{memberToken:X} /* {memberName} */ }},\n");
return rv;
}
@ -4892,7 +4900,7 @@ namespace Registrar {
/* The assembly must be a registered one, and only within the first 128 assemblies */
var assembly_name = GetAssemblyName (member.Module.Assembly);
var index = registered_assemblies.IndexOf (assembly_name);
var index = registered_assemblies.FindIndex (v => v.Name == assembly_name);
if (index < 0 || index > 127)
return CreateFullTokenReference (member);

18
tools/mtouch/Errors.designer.cs сгенерированный
Просмотреть файл

@ -4113,5 +4113,23 @@ namespace Xamarin.Bundler {
return ResourceManager.GetString("MX8042", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An exception occurred while validating the static registrar code for {0}: {1}.
/// </summary>
public static string MX8043 {
get {
return ResourceManager.GetString("MX8043", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The assembly {0} has been modified since the app was built, invalidating the generated static registrar code. The MVID for the loaded assembly is {1}, while the MVID for the assembly the generated static registrar code corresponds to is {2}..
/// </summary>
public static string MX8044 {
get {
return ResourceManager.GetString("MX8044", resourceCulture);
}
}
}
}

Просмотреть файл

@ -2171,4 +2171,16 @@
1: exception info
</comment>
</data>
<data name="MX8043" xml:space="preserve">
<value>An exception occurred while validating the static registrar code for {0}: {1}</value>
<comment>
0: name of an assembly
1: exception info
</comment>
</data>
<data name="MX8044" xml:space="preserve">
<value>The assembly {0} has been modified since the app was built, invalidating the generated static registrar code. The MVID for the loaded assembly is {1}, while the MVID for the assembly the generated static registrar code corresponds to is {2}.</value>
</data>
</root>