Browse Source

Merge pull request #4985 from AvaloniaUI/xaml-ignores-access-checks

Emit IgnoresAccessChecksToAttribute for runtime-generated XAML
pull/4990/head
Nikita Tsukanov 5 years ago
committed by GitHub
parent
commit
9fee5289b1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      build.sh
  2. 55
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
  3. 61
      tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs

2
build.sh

@ -47,7 +47,7 @@ if [ -f "$DOTNET_GLOBAL_FILE" ]; then
fi
# If dotnet is installed locally, and expected version is not set or installation matches the expected version
if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version) == "$DOTNET_VERSION") ]]; then
if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version) == "$DOTNET_VERSION") || "$SKIP_DOTNET_DOWNLOAD" == "1" ]]; then
export DOTNET_EXE="$(command -v dotnet)"
else
DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"

55
src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs

@ -26,6 +26,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
{
#if !RUNTIME_XAML_CECIL
private static SreTypeSystem _sreTypeSystem;
private static Type _ignoresAccessChecksFromAttribute;
private static ModuleBuilder _sreBuilder;
private static IXamlType _sreContextType;
private static XamlLanguageTypeMappings _sreMappings;
@ -94,8 +95,60 @@ namespace Avalonia.Markup.Xaml.XamlIl
_sreTypeSystem.CreateTypeBuilder(
_sreBuilder.DefineType("XamlIlContext")), _sreTypeSystem, _sreMappings,
_sreEmitMappings);
if (_ignoresAccessChecksFromAttribute == null)
_ignoresAccessChecksFromAttribute = EmitIgnoresAccessCheckAttributeDefinition(_sreBuilder);
}
static Type EmitIgnoresAccessCheckAttributeDefinition(ModuleBuilder builder)
{
var tb = builder.DefineType("System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute",
TypeAttributes.Class | TypeAttributes.Public, typeof(Attribute));
var field = tb.DefineField("_name", typeof(string), FieldAttributes.Private);
var propGet = tb.DefineMethod("get_AssemblyName", MethodAttributes.Public, typeof(string),
Array.Empty<Type>());
var propGetIl = propGet.GetILGenerator();
propGetIl.Emit(OpCodes.Ldarg_0);
propGetIl.Emit(OpCodes.Ldfld, field);
propGetIl.Emit(OpCodes.Ret);
var prop = tb.DefineProperty("AssemblyName", PropertyAttributes.None, typeof(string), Array.Empty<Type>());
prop.SetGetMethod(propGet);
var ctor = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard,
new[] { typeof(string) });
var ctorIl = ctor.GetILGenerator();
ctorIl.Emit(OpCodes.Ldarg_0);
ctorIl.Emit(OpCodes.Ldarg_1);
ctorIl.Emit(OpCodes.Stfld, field);
ctorIl.Emit(OpCodes.Ldarg_0);
ctorIl.Emit(OpCodes.Call, typeof(Attribute)
.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.First(x => x.GetParameters().Length == 0));
ctorIl.Emit(OpCodes.Ret);
tb.SetCustomAttribute(new CustomAttributeBuilder(
typeof(AttributeUsageAttribute).GetConstructor(new[] { typeof(AttributeTargets) }),
new object[] { AttributeTargets.Assembly },
new[] { typeof(AttributeUsageAttribute).GetProperty("AllowMultiple") },
new object[] { true }));
return tb.CreateTypeInfo();
}
static void EmitIgnoresAccessCheckToAttribute(AssemblyName assemblyName)
{
var name = assemblyName.Name;
if(string.IsNullOrWhiteSpace(name))
return;
var key = assemblyName.GetPublicKey();
if (key != null && key.Length != 0)
name += ", PublicKey=" + BitConverter.ToString(key).Replace("-", "").ToUpperInvariant();
_sreAsm.SetCustomAttribute(new CustomAttributeBuilder(
_ignoresAccessChecksFromAttribute.GetConstructors()[0],
new object[] { name }));
}
static object LoadSre(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode)
{
@ -118,6 +171,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
{
InitializeSre();
if (localAssembly?.GetName() != null)
EmitIgnoresAccessCheckToAttribute(localAssembly.GetName());
var asm = localAssembly == null ? null : _sreTypeSystem.GetAssembly(localAssembly);
var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri);
var clrPropertyBuilder = tb.DefineNestedType("ClrProperties_" + Guid.NewGuid().ToString("N"));

61
tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs

@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Designer;
using Avalonia.Remote.Protocol.Viewport;
using Xunit;
using Xunit.Extensions;
@ -31,19 +32,38 @@ namespace Avalonia.DesignerSupport.Tests
@"..\..\..\..\..\tests/Avalonia.DesignerSupport.TestApp/bin/$BUILD/netcoreapp3.1/",
"Avalonia.DesignerSupport.TestApp",
"Avalonia.DesignerSupport.TestApp.dll",
@"..\..\..\..\..\tests\Avalonia.DesignerSupport.TestApp\MainWindow.xaml"),
@"..\..\..\..\..\tests\Avalonia.DesignerSupport.TestApp\MainWindow.xaml",
"win32"),
InlineData(
@"..\..\..\..\..\samples\ControlCatalog.NetCore\bin\$BUILD\netcoreapp3.1\",
"ControlCatalog.NetCore",
"ControlCatalog.dll",
@"..\..\..\..\..\samples\ControlCatalog\MainWindow.xaml")]
@"..\..\..\..\..\samples\ControlCatalog\MainWindow.xaml",
"win32"),
InlineData(
@"..\..\..\..\..\tests/Avalonia.DesignerSupport.TestApp/bin/$BUILD/netcoreapp3.1/",
"Avalonia.DesignerSupport.TestApp",
"Avalonia.DesignerSupport.TestApp.dll",
@"..\..\..\..\..\tests\Avalonia.DesignerSupport.TestApp\MainWindow.xaml",
"avalonia-remote"),
InlineData(
@"..\..\..\..\..\samples\ControlCatalog.NetCore\bin\$BUILD\netcoreapp3.1\",
"ControlCatalog.NetCore",
"ControlCatalog.dll",
@"..\..\..\..\..\samples\ControlCatalog\MainWindow.xaml",
"avalonia-remote")]
public async Task Designer_In_Win32_Mode_Should_Provide_Valid_Hwnd(
string outputDir,
string executableName,
string assemblyName,
string xamlFile)
string xamlFile,
string method)
{
Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
outputDir = Path.GetFullPath(outputDir.Replace('\\', Path.DirectorySeparatorChar));
xamlFile = Path.GetFullPath(xamlFile.Replace('\\', Path.DirectorySeparatorChar));
if (method == "win32")
Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
var xaml = File.ReadAllText(xamlFile);
string buildType;
@ -56,6 +76,8 @@ namespace Avalonia.DesignerSupport.Tests
var sessionId = Guid.NewGuid();
long handle = 0;
bool success = false;
string error = null;
var resultMessageReceivedToken = new CancellationTokenSource();
@ -71,6 +93,18 @@ namespace Avalonia.DesignerSupport.Tests
if (msg is StartDesignerSessionMessage start)
{
Assert.Equal(sessionId, Guid.Parse(start.SessionId));
if (method == "avalonia-remote")
{
await conn.Send(new ClientSupportedPixelFormatsMessage
{
Formats = new[] { PixelFormat.Rgba8888 }
});
await conn.Send(new ClientViewportAllocatedMessage
{
DpiX = 96, DpiY = 96, Width = 1024, Height = 768
});
}
await conn.Send(new UpdateXamlMessage
{
AssemblyPath = Path.Combine(outputDir, assemblyName),
@ -80,8 +114,14 @@ namespace Avalonia.DesignerSupport.Tests
else if (msg is UpdateXamlResultMessage result)
{
if (result.Error != null)
{
error = result.Error;
outputHelper.WriteLine(result.Error);
handle = result.Handle != null ? long.Parse(result.Handle) : 0;
}
else
success = true;
if (method == "win32")
handle = result.Handle != null ? long.Parse(result.Handle) : 0;
resultMessageReceivedToken.Cancel();
conn.Dispose();
}
@ -91,7 +131,7 @@ namespace Avalonia.DesignerSupport.Tests
var cmdline =
$"exec --runtimeconfig \"{outputDir}{executableName}.runtimeconfig.json\" --depsfile \"{outputDir}{executableName}.deps.json\" "
+ $" \"{DesignerAppPath.Replace("$BUILD", buildType)}\" "
+ $"--transport tcp-bson://127.0.0.1:{port}/ --session-id {sessionId} --method win32 \"{outputDir}{executableName}.dll\"";
+ $"--transport tcp-bson://127.0.0.1:{port}/ --session-id {sessionId} --method {method} \"{outputDir}{executableName}.dll\"";
using (var proc = new Process
{
@ -128,10 +168,15 @@ namespace Avalonia.DesignerSupport.Tests
}
proc.WaitForExit();
var stdout = proc.StandardOutput.ReadToEnd();
var stderr = proc.StandardError.ReadToEnd();
Assert.True(cancelled,
$"Message Not Received.\n" + proc.StandardOutput.ReadToEnd() + "\n" +
proc.StandardError.ReadToEnd());
Assert.NotEqual(0, handle);
stderr + "\n" + stdout);
Assert.True(success, error);
if (method == "win32")
Assert.NotEqual(0, handle);
}
}

Loading…
Cancel
Save