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

Add IgnoresAccessChecksToAttribute into generated assemblies #494

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/IKVM.MSBuild.Tasks/IkvmReferenceItemPrepare.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ protected override async Task<bool> ExecuteAsync(CancellationToken cancellationT
/// <summary>
/// Attempts to load the state file.
/// </summary>
/// <param name="cancellationToken"></param>
internal void LoadState()
{
if (StateFile != null && File.Exists(StateFile))
Expand Down
382 changes: 181 additions & 201 deletions src/IKVM.Runtime/AttributeHelper.cs

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions src/IKVM.Runtime/DynamicClassLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ public DynamicClassLoader GetOrCreate(RuntimeClassLoader loader)
if (loader is RuntimeAssemblyClassLoader acl)
{
var name = acl.MainAssembly.GetName().Name + context.Options.DynamicAssemblySuffixAndPublicKey;

foreach (var attr in acl.MainAssembly.GetCustomAttributes<InternalsVisibleToAttribute>())
{
if (attr.AssemblyName == name)
Expand Down Expand Up @@ -513,7 +514,7 @@ private static SerializationInfo ToInfo(byte[] publicKey)

public static ModuleBuilder CreateModuleBuilder(RuntimeContext context)
{
AssemblyName name = new AssemblyName();
var name = new AssemblyName();
name.Name = "ikvm_dynamic_assembly__" + (uint)Environment.TickCount;
return CreateModuleBuilder(context, name);
}
Expand All @@ -523,7 +524,7 @@ public static ModuleBuilder CreateModuleBuilder(RuntimeContext context, Assembly
var now = DateTime.Now;
name.Version = new Version(now.Year, (now.Month * 100) + now.Day, (now.Hour * 100) + now.Minute, (now.Second * 1000) + now.Millisecond);
var attribs = new List<CustomAttributeBuilder>();
AssemblyBuilderAccess access = AssemblyBuilderAccess.Run;
var access = AssemblyBuilderAccess.Run;

#if NETFRAMEWORK
if (!AppDomain.CurrentDomain.IsFullyTrusted)
Expand All @@ -546,7 +547,7 @@ public static ModuleBuilder CreateModuleBuilder(RuntimeContext context, Assembly
var moduleBuilder = assemblyBuilder.DefineDynamicModule(name.Name);
#endif

moduleBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(IKVM.Attributes.JavaModuleAttribute).GetConstructor(Type.EmptyTypes), new object[0]));
moduleBuilder.SetCustomAttribute(new CustomAttributeBuilder(typeof(IKVM.Attributes.JavaModuleAttribute).GetConstructor(Type.EmptyTypes), Array.Empty<object>()));
return moduleBuilder;
}

Expand Down
141 changes: 82 additions & 59 deletions src/IKVM.Runtime/RuntimeByteCodeJavaType.JavaTypeImpl.cs

Large diffs are not rendered by default.

24 changes: 14 additions & 10 deletions src/IKVM.Runtime/RuntimeJavaType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -867,32 +867,36 @@ internal void SetFields(RuntimeJavaField[] fields)
internal virtual string SigName => "L" + Name + ";";

// returns true iff wrapper is allowed to access us
internal bool IsAccessibleFrom(RuntimeJavaType wrapper)

/// <summary>
/// Returns <c>true</c> if the specified type is able to access us.
/// </summary>
/// <param name="wrapper"></param>
/// <returns></returns>
internal bool IsAccessibleFrom(RuntimeJavaType other)
{
return IsPublic
|| (IsInternal && InternalsVisibleTo(wrapper))
|| IsPackageAccessibleFrom(wrapper);
return IsPublic || (IsInternal && InternalsVisibleTo(other)) || IsPackageAccessibleFrom(other);
}

internal bool InternalsVisibleTo(RuntimeJavaType wrapper)
{
return GetClassLoader().InternalsVisibleToImpl(this, wrapper);
}

internal virtual bool IsPackageAccessibleFrom(RuntimeJavaType wrapper)
internal virtual bool IsPackageAccessibleFrom(RuntimeJavaType other)
{
if (MatchingPackageNames(name, wrapper.name))
if (MatchingPackageNames(name, other.name))
{
#if IMPORTER
CompilerClassLoader ccl = GetClassLoader() as CompilerClassLoader;
if (ccl != null)
if (GetClassLoader() is CompilerClassLoader ccl)
{
// this is a hack for multi target -sharedclassloader compilation
// (during compilation we have multiple CompilerClassLoader instances to represent the single shared runtime class loader)
return ccl.IsEquivalentTo(wrapper.GetClassLoader());
return ccl.IsEquivalentTo(other.GetClassLoader());
}
#endif
return GetClassLoader() == wrapper.GetClassLoader();

return GetClassLoader() == other.GetClassLoader();
}
else
{
Expand Down
1 change: 1 addition & 0 deletions src/IKVM.Runtime/UnicodeUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ internal static string EscapeInvalidSurrogates(string str)
}
}
}

return str;
}

Expand Down
1 change: 1 addition & 0 deletions src/IKVM.Tools.Importer.Tests/IkvmImporterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public async Task CanImportSimpleTest(string ikvmFramework, string targetFramewo
File.Exists(asm).Should().BeTrue();
new FileInfo(asm).Length.Should().BeGreaterThanOrEqualTo(128);
}

}

}
112 changes: 74 additions & 38 deletions src/IKVM.Tools.Importer/CompilerClassLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ Jeroen Frijters
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
Expand Down Expand Up @@ -125,19 +124,6 @@ internal AssemblyName GetAssemblyName()
return assemblyBuilder.GetName();
}

private static PermissionSet Combine(PermissionSet p1, PermissionSet p2)
{
if (p1 == null)
{
return p2;
}
if (p2 == null)
{
return p1;
}
return p1.Union(p2);
}

internal ModuleBuilder CreateModuleBuilder()
{
var name = new AssemblyName();
Expand Down Expand Up @@ -273,17 +259,16 @@ private RuntimeJavaType PeerLoad(string name)

private RuntimeJavaType GetTypeWrapperCompilerHook(string name)
{
RemapperTypeWrapper rtw;
if (remapped.TryGetValue(name, out rtw))
if (remapped.TryGetValue(name, out var rtw))
{
return rtw;
}
else
{
Jar.Item itemRef;
if (classes.TryGetValue(name, out itemRef))
if (classes.TryGetValue(name, out var itemRef))
{
classes.Remove(name);

ClassFile f;
try
{
Expand Down Expand Up @@ -326,6 +311,7 @@ private RuntimeJavaType GetTypeWrapperCompilerHook(string name)
break;
}
}

if (!found)
{
f.SetInternal();
Expand Down Expand Up @@ -370,12 +356,14 @@ private RuntimeJavaType GetTypeWrapperCompilerHook(string name)
{
itemRef.MarkAsStub();
}

int pos = f.Name.LastIndexOf('.');
if (pos != -1)
{
string manifestJar = options.IsClassesJar(itemRef.Jar) ? null : itemRef.Jar.Name;
var manifestJar = options.IsClassesJar(itemRef.Jar) ? null : itemRef.Jar.Name;
packages.DefinePackage(f.Name.Substring(0, pos), manifestJar);
}

return tw;
}
catch (ClassFormatError x)
Expand All @@ -396,12 +384,14 @@ private RuntimeJavaType GetTypeWrapperCompilerHook(string name)
{
Context.StaticCompiler.IssueMessage(options, Message.NoClassDefFoundError, name, x.Message);
}

Context.StaticCompiler.IssueMessage(options, Message.ClassNotFound, x.Message);
}
catch (RetargetableJavaException x)
{
Context.StaticCompiler.IssueMessage(options, Message.GenericUnableToCompileError, name, x.GetType().Name, x.Message);
}

Context.StaticCompiler.SuppressWarning(options, Message.ClassNotFound, name);
return null;
}
Expand All @@ -420,57 +410,63 @@ internal bool IsEquivalentTo(RuntimeClassLoader other)
{
return true;
}
CompilerClassLoader ccl = other as CompilerClassLoader;

var ccl = other as CompilerClassLoader;
if (ccl != null && options.sharedclassloader != null && options.sharedclassloader.Contains(ccl))
{
if (!internalsVisibleTo.Contains(ccl))
{
AddInternalsVisibleToAttribute(ccl);
}

return true;
}

return false;
}

internal override bool InternalsVisibleToImpl(RuntimeJavaType wrapper, RuntimeJavaType friend)
{
Debug.Assert(wrapper.GetClassLoader() == this);
RuntimeClassLoader other = friend.GetClassLoader();
var other = friend.GetClassLoader();

// TODO ideally we should also respect InternalsVisibleToAttribute.Annotation here
if (this == other || internalsVisibleTo.Contains(other))
{
return true;
}
CompilerClassLoader ccl = other as CompilerClassLoader;

var ccl = other as CompilerClassLoader;
if (ccl != null)
{
AddInternalsVisibleToAttribute(ccl);
return true;
}

return false;
}

private void AddInternalsVisibleToAttribute(CompilerClassLoader ccl)
{
internalsVisibleTo.Add(ccl);
AssemblyBuilder asm = ccl.assemblyBuilder;
AssemblyName asmName = asm.GetName();
string name = asmName.Name;
byte[] pubkey = asmName.GetPublicKey();

var asm = ccl.assemblyBuilder;
var asmName = asm.GetName();
var name = asmName.Name;

var pubkey = asmName.GetPublicKey();
if (pubkey == null && asmName.KeyPair != null)
{
pubkey = asmName.KeyPair.PublicKey;
}

if (pubkey != null && pubkey.Length != 0)
{
StringBuilder sb = new StringBuilder(name);
var sb = new StringBuilder(name);
sb.Append(", PublicKey=");
foreach (byte b in pubkey)
{
sb.AppendFormat("{0:X2}", b);
}
name = sb.ToString();
}

Context.AttributeHelper.SetInternalsVisibleToAttribute(this.assemblyBuilder, name);
}

Expand Down Expand Up @@ -555,7 +551,7 @@ void PrepareSave()

void Save()
{
ModuleBuilder mb = GetTypeWrapperFactory().ModuleBuilder;
var mb = GetTypeWrapperFactory().ModuleBuilder;
if (targetIsModule)
{
// HACK force all referenced assemblies to end up as references in the assembly
Expand All @@ -565,30 +561,35 @@ void Save()
// assemblies in the ikvm.exports resource.
for (int i = 0; i < referencedAssemblies.Length; i++)
{
Type[] types = referencedAssemblies[i].MainAssembly.GetExportedTypes();
var types = referencedAssemblies[i].MainAssembly.GetExportedTypes();
if (types.Length > 0)
{
mb.GetTypeToken(types[0]);
}
}
}

// initialize the global functions for the module
mb.CreateGlobalFunctions();

// signify we are creating a Java module
AddJavaModuleAttribute(mb);

// ignore access checks to referenced Java modules
AddIgnoresAccessChecksToAttribute(mb);

// add a package list and export map
if (options.sharedclassloader == null || options.sharedclassloader[0] == this)
{
var packageListAttributeCtor = Context.Resolver.ResolveRuntimeType(typeof(PackageListAttribute).FullName).GetConstructor(new Type[] { Context.Types.String, Context.Types.String.MakeArrayType() });
foreach (object[] args in packages.ToArray())
var packageListAttributeCtor = Context.Resolver.ResolveRuntimeType(typeof(PackageListAttribute).FullName).GetConstructor(new[] { Context.Types.String, Context.Types.String.MakeArrayType() });
foreach (var args in packages.ToArray())
{
args[1] = UnicodeUtil.EscapeInvalidSurrogates((string[])args[1]);
mb.SetCustomAttribute(new CustomAttributeBuilder(packageListAttributeCtor, args));
}

// We can't add the resource when we're a module, because a multi-module assembly has a single resource namespace
// and since you cannot combine -target:module with -sharedclassloader we don't need an export map
// (the wildcard exports have already been added above, by making sure that we statically reference the assemblies).
if (!targetIsModule)
if (targetIsModule == false)
{
WriteExportMap();
}
Expand All @@ -597,6 +598,7 @@ void Save()
if (targetIsModule)
{
Tracer.Info(Tracer.Compiler, "CompilerClassLoader saving {0} in {1}", assemblyFile, assemblyDir);

try
{
GetTypeWrapperFactory().ModuleBuilder.__Save(options.pekind, options.imageFileMachine);
Expand Down Expand Up @@ -629,6 +631,40 @@ void Save()
}
}

/// <summary>
/// Adds a 'IgnoresAccessChecksToAttribute' type to the assembly and attributes on the assembly that ignore
/// access checks to all Java modules which are referenced. This ensures package-private references across
/// assemblies are possible.
/// </summary>
/// <param name="mb"></param>
void AddIgnoresAccessChecksToAttribute(ModuleBuilder mb)
{
if (targetIsModule == false)
{
// add IgnoresAccessChecksToAttribute type
var iactBuilder = mb.DefineType("System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute", TypeAttributes.Class | TypeAttributes.Sealed, Context.Types.Attribute);
Context.AttributeHelper.SetAttributeUsage(iactBuilder, AttributeTargets.Assembly, true);

// add .ctor to type
var ctorBuilder = iactBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { Context.Types.String });
var ctorIL = ctorBuilder.GetILGenerator();
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Call, Context.Types.Attribute.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));
ctorIL.Emit(OpCodes.Ret);

// create type
var iact = iactBuilder.CreateType();
var iactCtor = iact.GetConstructor(new[] { Context.Types.String });

// add IgnoresAccessChecksToAttribute to each referenced assembly
var hs = new HashSet<RuntimeAssemblyClassLoader>();
for (int i = 0; i < referencedAssemblies.Length; i++)
if (hs.Add(referencedAssemblies[i]))
if (Context.AttributeHelper.IsJavaModule(referencedAssemblies[i].MainAssembly.ManifestModule))
assemblyBuilder.SetCustomAttribute(new CustomAttributeBuilder(iactCtor, new[] { UnicodeUtil.EscapeInvalidSurrogates(referencedAssemblies[i].MainAssembly.FullName) }));
}
}

void AddJavaModuleAttribute(ModuleBuilder mb)
{
var typeofJavaModuleAttribute = Context.Resolver.ResolveRuntimeType(typeof(JavaModuleAttribute).FullName);
Expand Down
Loading