From b2f73492f58e8e7dca8d1793cf88b6932266d8f2 Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Thu, 20 Sep 2018 10:20:37 +0100 Subject: [PATCH] Fix method wiping (#1448) * Fix wiping assemblies that contain references to others in same directory * Fix generated IL for reporting calls to wiped methods * Add E2E test for method wiping --- samples/MonoSanity/wwwroot/index.html | 18 ++++++++++++++++++ samples/MonoSanity/wwwroot/loader.js | 1 + samples/MonoSanityClient/Examples.cs | 6 ++++++ .../Core/ILWipe/MethodWipedExceptionMethod.cs | 4 +++- .../Core/ILWipe/WipeAssembly.cs | 6 ++++++ .../Tests/MonoSanityTest.cs | 10 +++++++++- 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/samples/MonoSanity/wwwroot/index.html b/samples/MonoSanity/wwwroot/index.html index 6fefd738b6..91ae74f88d 100644 --- a/samples/MonoSanity/wwwroot/index.html +++ b/samples/MonoSanity/wwwroot/index.html @@ -36,6 +36,14 @@ +
+ Invoke wiped method +
+ +
+
+
+
Call JS from .NET
@@ -103,6 +111,16 @@ } }; + el('invokeWipedMethod').onsubmit = function (evt) { + evt.preventDefault(); + try { + invokeMonoMethod('MonoSanityClient', 'MonoSanityClient', 'Examples', 'InvokeWipedMethod', []); + el('invokeWipedMethodStackTrace').value = 'WARNING: No exception occurred'; + } catch (ex) { + el('invokeWipedMethodStackTrace').value = ex.toString(); + } + }; + el('callJs').onsubmit = function (evt) { evt.preventDefault(); var expression = el('callJsEvalExpression').value; diff --git a/samples/MonoSanity/wwwroot/loader.js b/samples/MonoSanity/wwwroot/loader.js index 7eca77256c..3eda2fae71 100644 --- a/samples/MonoSanity/wwwroot/loader.js +++ b/samples/MonoSanity/wwwroot/loader.js @@ -80,6 +80,7 @@ 'mscorlib', 'System', 'System.Core', + 'System.Net.Http', ]; var allAssemblyUrls = loadAssemblyUrls diff --git a/samples/MonoSanityClient/Examples.cs b/samples/MonoSanityClient/Examples.cs index f2dd3af794..cf81933b8a 100644 --- a/samples/MonoSanityClient/Examples.cs +++ b/samples/MonoSanityClient/Examples.cs @@ -5,6 +5,7 @@ using WebAssembly.JSInterop; using System; using System.Runtime.InteropServices; using System.Text; +using System.Net.Http; namespace MonoSanityClient { @@ -30,6 +31,11 @@ namespace MonoSanityClient throw new InvalidOperationException(message); } + public static void InvokeWipedMethod() + { + new HttpClientHandler(); + } + public static string EvaluateJavaScript(string expression) { var result = InternalCalls.InvokeJSUnmarshalled(out var exceptionMessage, "evaluateJsExpression", expression, null, null); diff --git a/src/Microsoft.AspNetCore.Blazor.BuildTools/Core/ILWipe/MethodWipedExceptionMethod.cs b/src/Microsoft.AspNetCore.Blazor.BuildTools/Core/ILWipe/MethodWipedExceptionMethod.cs index 0634e77032..82d7c4d8e4 100644 --- a/src/Microsoft.AspNetCore.Blazor.BuildTools/Core/ILWipe/MethodWipedExceptionMethod.cs +++ b/src/Microsoft.AspNetCore.Blazor.BuildTools/Core/ILWipe/MethodWipedExceptionMethod.cs @@ -23,7 +23,8 @@ namespace Microsoft.AspNetCore.Blazor.BuildTools.Core.ILWipe // } // } var ilWipeHelpersType = new TypeDefinition("ILWipe", "ILWipeHelpers", - TypeAttributes.NotPublic | TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit); + TypeAttributes.NotPublic | TypeAttributes.Class | TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, + moduleDefinition.TypeSystem.Object); moduleDefinition.Types.Add(ilWipeHelpersType); var methodAttributes = @@ -38,6 +39,7 @@ namespace Microsoft.AspNetCore.Blazor.BuildTools.Core.ILWipe var notImplExceptionType = ImportEquivalentTypeFromMscorlib(moduleDefinition, typeof(NotImplementedException)); var notImplExceptionCtor = new MethodReference(".ctor", moduleDefinition.TypeSystem.Void, notImplExceptionType); + notImplExceptionCtor.HasThis = true; notImplExceptionCtor.Parameters.Add(new ParameterDefinition(moduleDefinition.TypeSystem.String)); var il = createMethodWipedExceptionMethod.Body.GetILProcessor(); diff --git a/src/Microsoft.AspNetCore.Blazor.BuildTools/Core/ILWipe/WipeAssembly.cs b/src/Microsoft.AspNetCore.Blazor.BuildTools/Core/ILWipe/WipeAssembly.cs index 3adf8f601a..cff68bf17f 100644 --- a/src/Microsoft.AspNetCore.Blazor.BuildTools/Core/ILWipe/WipeAssembly.cs +++ b/src/Microsoft.AspNetCore.Blazor.BuildTools/Core/ILWipe/WipeAssembly.cs @@ -43,6 +43,12 @@ namespace Microsoft.AspNetCore.Blazor.BuildTools.Core.ILWipe } } + // Also resolve referenced assemblies in the same directory + if (moduleDefinition.AssemblyResolver is DefaultAssemblyResolver resolver) + { + resolver.AddSearchDirectory(Path.GetDirectoryName(inputPath)); + } + moduleDefinition.Write(outputPath); } } diff --git a/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/MonoSanityTest.cs b/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/MonoSanityTest.cs index 6bc3fdc16e..8585fc20a2 100644 --- a/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/MonoSanityTest.cs +++ b/test/Microsoft.AspNetCore.Blazor.E2ETest/Tests/MonoSanityTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure; @@ -68,6 +68,14 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests Assert.Contains("Hello from test", GetValue(Browser, "triggerExceptionMessageStackTrace")); } + [Fact] + public void ProvidesDiagnosticIfInvokingWipedMethod() + { + Browser.FindElement(By.CssSelector("#invokeWipedMethod button")).Click(); + + Assert.Contains("System.NotImplementedException: Cannot invoke method because it was wiped. See stack trace for details.", GetValue(Browser, "invokeWipedMethodStackTrace")); + } + [Fact] public void CanCallJavaScriptFromDotNet() {