Skip to content

Commit d793586

Browse files
radicalmaraf
andauthored
[wasm] ManagedToNativeGenerator: Skip unmanaged dlls (#81066)
* [wasm] ManagedToNativeGenerator: Skip unmanaged dlls .. instead crashing with an exception like: ``` src/mono/wasm/build/WasmApp.Native.targets(296,5): error MSB4018: (NETCORE_ENGINEERING_TELEMETRY=Build) The "ManagedToNativeGenerator" task failed unexpectedly. System.BadImageFormatException: This PE image is not a managed executable. at System.Reflection.MetadataLoadContext.LoadFromStreamCore(Stream peStream) at System.Reflection.MetadataLoadContext.LoadFromAssemblyPath(String assemblyPath) at PInvokeTableGenerator.Generate(String[] pinvokeModules, String[] assemblies, String outputPath) in /_/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs:line 42 at ManagedToNativeGenerator.ExecuteInternal() in /_/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs:line 68 at ManagedToNativeGenerator.Execute() in /_/src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs:line 53 at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute() at Microsoft.Build.BackEnd.TaskBuilder.ExecuteInstantiatedTask(ITaskExecutionHost taskExecutionHost, TaskLoggingContext taskLoggingContext, TaskHost taskHost, ItemBucket bucket, TaskExecutionMode howToExecuteTask) ``` The wasm targets currently are not able to differentiate the managed assemblies from the unmanaged ones. so it needs to be handled here. * [wasm] WasmAppHost: Add support for host arguments * Drop reallocation of managed dlls. Co-authored-by: Marek Fišera <[email protected]>
1 parent e463920 commit d793586

File tree

6 files changed

+73
-13
lines changed

6 files changed

+73
-13
lines changed

src/mono/wasm/host/CommonConfiguration.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ internal sealed class CommonConfiguration
2222
public WasmHost Host { get; init; }
2323
public HostConfig HostConfig { get; init; }
2424
public WasmHostProperties HostProperties { get; init; }
25+
public IEnumerable<string> HostArguments { get; init; }
2526

2627
private string? hostArg;
2728
private string? _runtimeConfigPath;
@@ -30,11 +31,13 @@ internal sealed class CommonConfiguration
3031

3132
private CommonConfiguration(string[] args)
3233
{
34+
List<string> hostArgsList = new();
3335
var options = new OptionSet
3436
{
3537
{ "debug|d", "Start debug server", _ => Debugging = true },
3638
{ "host|h=", "Host config name", v => hostArg = v },
37-
{ "runtime-config|r=", "runtimeconfig.json path for the app", v => _runtimeConfigPath = v }
39+
{ "runtime-config|r=", "runtimeconfig.json path for the app", v => _runtimeConfigPath = v },
40+
{ "extra-host-arg=", "Extra argument to be passed to the host", hostArgsList.Add },
3841
};
3942

4043
RemainingArgs = options.Parse(args);
@@ -95,6 +98,9 @@ private CommonConfiguration(string[] args)
9598
if (!Enum.TryParse(HostConfig.HostString, ignoreCase: true, out WasmHost wasmHost))
9699
throw new CommandLineException($"Unknown host {HostConfig.HostString} in config named {HostConfig.Name}");
97100
Host = wasmHost;
101+
102+
hostArgsList.AddRange(HostConfig.HostArguments);
103+
HostArguments = hostArgsList;
98104
}
99105

100106
public ProxyOptions ToProxyOptions()

src/mono/wasm/host/JSEngineHost.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ public static async Task<int> InvokeAsync(CommonConfiguration commonArgs,
3737

3838
private async Task<int> RunAsync()
3939
{
40-
string[] engineArgs = Array.Empty<string>();
41-
4240
string engineBinary = _args.Host switch
4341
{
4442
WasmHost.V8 => "v8",
@@ -79,9 +77,10 @@ private async Task<int> RunAsync()
7977
args.Add("--expose_wasm");
8078
}
8179

80+
args.AddRange(_args.CommonConfig.HostArguments);
81+
8282
args.Add(_args.JSPath!);
8383

84-
args.AddRange(engineArgs);
8584
if (_args.Host is WasmHost.V8 or WasmHost.JavaScriptCore)
8685
{
8786
// v8/jsc want arguments to the script separated by "--", others don't

src/mono/wasm/host/RuntimeConfigJson.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Text.Json;
67
using System.Text.Json.Serialization;
@@ -32,6 +33,7 @@ internal sealed record WasmHostProperties(
3233

3334
internal sealed record HostConfig(string? Name, [property: JsonPropertyName("host")] string? HostString)
3435
{
36+
[property: JsonPropertyName("host-args")] public string[] HostArguments { get; set; } = Array.Empty<string>();
3537
// using an explicit property because the deserializer doesn't like
3638
// extension data in the record constructor
3739
[property: JsonExtensionData] public Dictionary<string, JsonElement>? Properties { get; set; }

src/tasks/WasmAppBuilder/IcallTableGenerator.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public IcallTableGenerator(Func<string, string> fixupSymbolName, TaskLoggingHelp
3434
// The runtime icall table should be generated using
3535
// mono --print-icall-table
3636
//
37-
public IEnumerable<string> Generate(string? runtimeIcallTableFile, string[] assemblies, string? outputPath)
37+
public IEnumerable<string> Generate(string? runtimeIcallTableFile, IEnumerable<string> assemblies, string? outputPath)
3838
{
3939
_icalls.Clear();
4040
_signatures.Clear();
@@ -44,9 +44,13 @@ public IEnumerable<string> Generate(string? runtimeIcallTableFile, string[] asse
4444

4545
var resolver = new PathAssemblyResolver(assemblies);
4646
using var mlc = new MetadataLoadContext(resolver, "System.Private.CoreLib");
47-
foreach (var aname in assemblies)
47+
foreach (var asmPath in assemblies)
4848
{
49-
var a = mlc.LoadFromAssemblyPath(aname);
49+
if (!File.Exists(asmPath))
50+
throw new LogAsErrorException($"Cannot find assembly {asmPath}");
51+
52+
Log.LogMessage(MessageImportance.Low, $"Loading {asmPath} to scan for icalls");
53+
var a = mlc.LoadFromAssemblyPath(asmPath);
5054
foreach (var type in a.GetTypes())
5155
ProcessType(type);
5256
}

src/tasks/WasmAppBuilder/ManagedToNativeGenerator.cs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Diagnostics.CodeAnalysis;
7+
using System.IO;
68
using System.Linq;
9+
using System.Reflection.PortableExecutable;
710
using System.Text;
811
using Microsoft.Build.Framework;
912
using Microsoft.Build.Utilities;
1013

1114
public class ManagedToNativeGenerator : Task
1215
{
1316
[Required]
14-
public string[]? Assemblies { get; set; }
17+
public string[] Assemblies { get; set; } = Array.Empty<string>();
1518

1619
public string? RuntimeIcallTableFile { get; set; }
1720

@@ -62,12 +65,14 @@ public override bool Execute()
6265

6366
private void ExecuteInternal()
6467
{
68+
List<string> managedAssemblies = FilterOutUnmanagedBinaries(Assemblies);
69+
6570
var pinvoke = new PInvokeTableGenerator(FixupSymbolName, Log);
6671
var icall = new IcallTableGenerator(FixupSymbolName, Log);
6772

6873
IEnumerable<string> cookies = Enumerable.Concat(
69-
pinvoke.Generate(PInvokeModules, Assemblies!, PInvokeOutputPath!),
70-
icall.Generate(RuntimeIcallTableFile, Assemblies!, IcallOutputPath)
74+
pinvoke.Generate(PInvokeModules, managedAssemblies, PInvokeOutputPath!),
75+
icall.Generate(RuntimeIcallTableFile, managedAssemblies, IcallOutputPath)
7176
);
7277

7378
var m2n = new InterpToNativeGenerator(Log);
@@ -110,4 +115,43 @@ public string FixupSymbolName(string name)
110115
_symbolNameFixups[name] = fixedName;
111116
return fixedName;
112117
}
118+
119+
private List<string> FilterOutUnmanagedBinaries(string[] assemblies)
120+
{
121+
List<string> managedAssemblies = new(assemblies.Length);
122+
foreach (string asmPath in Assemblies)
123+
{
124+
if (!File.Exists(asmPath))
125+
throw new LogAsErrorException($"Cannot find assembly {asmPath}");
126+
127+
try
128+
{
129+
if (!IsManagedAssembly(asmPath))
130+
{
131+
Log.LogMessage(MessageImportance.Low, $"Skipping unmanaged {asmPath}.");
132+
continue;
133+
}
134+
}
135+
catch (Exception ex)
136+
{
137+
Log.LogMessage(MessageImportance.Low, $"Failed to read assembly {asmPath}: {ex}");
138+
throw new LogAsErrorException($"Failed to read assembly {asmPath}: {ex.Message}");
139+
}
140+
141+
managedAssemblies.Add(asmPath);
142+
}
143+
144+
return managedAssemblies;
145+
}
146+
147+
private static bool IsManagedAssembly(string filePath)
148+
{
149+
if (!File.Exists(filePath))
150+
return false;
151+
152+
using FileStream fileStream = File.OpenRead(filePath);
153+
using PEReader reader = new(fileStream, PEStreamOptions.Default);
154+
return reader.HasMetadata;
155+
}
156+
113157
}

src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public PInvokeTableGenerator(Func<string, string> fixupSymbolName, TaskLoggingHe
2424
_fixupSymbolName = fixupSymbolName;
2525
}
2626

27-
public IEnumerable<string> Generate(string[] pinvokeModules, string[] assemblies, string outputPath)
27+
public IEnumerable<string> Generate(string[] pinvokeModules, IEnumerable<string> assemblies, string outputPath)
2828
{
2929
var modules = new Dictionary<string, string>();
3030
foreach (var module in pinvokeModules)
@@ -37,9 +37,14 @@ public IEnumerable<string> Generate(string[] pinvokeModules, string[] assemblies
3737

3838
var resolver = new PathAssemblyResolver(assemblies);
3939
using var mlc = new MetadataLoadContext(resolver, "System.Private.CoreLib");
40-
foreach (var aname in assemblies)
40+
41+
foreach (var asmPath in assemblies)
4142
{
42-
var a = mlc.LoadFromAssemblyPath(aname);
43+
if (!File.Exists(asmPath))
44+
throw new LogAsErrorException($"Cannot find assembly {asmPath}");
45+
46+
Log.LogMessage(MessageImportance.Low, $"Loading {asmPath} to scan for pinvokes");
47+
var a = mlc.LoadFromAssemblyPath(asmPath);
4348
foreach (var type in a.GetTypes())
4449
CollectPInvokes(pinvokes, callbacks, signatures, type);
4550
}

0 commit comments

Comments
 (0)