Skip to content
Open
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
37 changes: 37 additions & 0 deletions src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,43 @@ public void UnsupportedOSPlatformPInvokeIsSkipped(Configuration config, bool aot
Assert.DoesNotContain("WASM0062", output);
}

[Theory]
[BuildAndRun(aot: false)]
[TestCategory("native-mono")]
public async Task VersionedOSPlatformPInvokeIsIncluded(Configuration config, bool aot)
{
// Regression coverage for https://github.com/dotnet/runtime/issues/132297:
// a versioned platform attribute like [SupportedOSPlatform("browser1.0")] must still
// be treated as matching TargetOS=browser, so the pinvoke must be kept (not silently
// filtered out), while a versioned attribute for a different OS (e.g. "windows1.0")
// must still be filtered out.
string extraItems = @"<NativeFileReference Include=""versioned-osplatform.c"" />";
ProjectInfo info = CopyTestAsset(config, aot, TestAsset.WasmBasicTestApp, "versioned_osplatform_pinvoke",
extraItems: extraItems, extraProperties: "<WasmBuildNative>true</WasmBuildNative>");
ReplaceFile(Path.Combine("Common", "Program.cs"), Path.Combine(BuildEnvironment.TestAssetsPath, "EntryPoints", "PInvoke", "VersionedOSPlatform.cs"));
File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "native-libs", "versioned-osplatform.c"), Path.Combine(_projectDir, "versioned-osplatform.c"));

(_, string output) = BuildProject(info, config, new BuildOptions(AssertAppBundle: false, AOT: aot), isNativeBuild: true);
Assert.DoesNotContain("WASM0001", output);

string objDir = Path.Combine(_projectDir, "obj", config.ToString(), DefaultTargetFramework, "wasm", "for-build");
string pinvokeTableFileName = IsCoreClrRuntime ? "callhelpers-pinvoke.cpp" : "pinvoke-table.h";
string pinvokeTable = File.ReadAllText(Path.Combine(objDir, pinvokeTableFileName));

string includedPInvokeTableEntry = IsCoreClrRuntime
? "DllImportEntry(versioned_browser_add)"
: "\"versioned_browser_add\", versioned_browser_add";
Assert.Contains(includedPInvokeTableEntry, pinvokeTable);

string excludedPInvokeTableEntry = IsCoreClrRuntime
? "DllImportEntry(versioned_windows_add)"
: "\"versioned_windows_add\", versioned_windows_add";
Assert.DoesNotContain(excludedPInvokeTableEntry, pinvokeTable);

RunResult result = await RunForBuildWithDotnetRun(new BrowserRunOptions(config, TestScenario: "DotnetRun", ExpectedExitCode: 42));
Assert.Contains("sum: 42", result.TestOutput);
}

[Theory]
[BuildAndRun(aot: true, config: Configuration.Release)]
[TestCategory("native-mono")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

Console.WriteLine($"TestOutput -> sum: {VersionedBrowserInterop.versioned_browser_add(19, 23)}");
return 42;

// Regression coverage for https://github.com/dotnet/runtime/issues/132297:
// a versioned platform attribute like [SupportedOSPlatform("browser1.0")] must still match
// TargetOS=browser, so this pinvoke must be included in the generated pinvoke table and
// callable at runtime.
[SupportedOSPlatform("browser1.0")]
internal static class VersionedBrowserInterop
{
[DllImport("versioned-osplatform")]
public static extern int versioned_browser_add(int a, int b);
}

// A versioned platform attribute for a different OS must not match TargetOS=browser, so this
// pinvoke must be skipped and must not appear in the generated pinvoke table.
[SupportedOSPlatform("windows1.0")]
internal static class VersionedWindowsInterop
{
[DllImport("versioned-osplatform")]
public static extern int versioned_windows_add(int a, int b);
}
4 changes: 4 additions & 0 deletions src/mono/wasm/testassets/native-libs/versioned-osplatform.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
int versioned_browser_add(int a, int b)
{
return a + b;
}
20 changes: 18 additions & 2 deletions src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,15 +291,15 @@ private PlatformSupport EvaluatePlatformAttributes(IList<CustomAttributeData> at
{
if (cattr.AttributeType.FullName == "System.Runtime.Versioning.UnsupportedOSPlatformAttribute" &&
cattr.ConstructorArguments.Count > 0 &&
cattr.ConstructorArguments[0].Value?.ToString() == _targetOS)
MatchesTargetOS(cattr.ConstructorArguments[0].Value?.ToString()))
{
return PlatformSupport.Unsupported;
}
if (cattr.AttributeType.FullName == "System.Runtime.Versioning.SupportedOSPlatformAttribute" &&
cattr.ConstructorArguments.Count > 0)
{
hasSupportedOSPlatform = true;
if (cattr.ConstructorArguments[0].Value?.ToString() == _targetOS)
if (MatchesTargetOS(cattr.ConstructorArguments[0].Value?.ToString()))
hasSupportedTarget = true;
}
}
Expand All @@ -314,6 +314,22 @@ private PlatformSupport EvaluatePlatformAttributes(IList<CustomAttributeData> at

return PlatformSupport.Unknown;
}

private bool MatchesTargetOS(string? platformName)
{
if (string.Equals(platformName, _targetOS, StringComparison.OrdinalIgnoreCase))
return true;

if (platformName?.StartsWith(_targetOS, StringComparison.OrdinalIgnoreCase) != true)
return false;

#if NETFRAMEWORK
string version = platformName.Substring(_targetOS.Length);
#else
ReadOnlySpan<char> version = platformName.AsSpan(_targetOS.Length);
#endif
return Version.TryParse(version, out _);
}
}

internal sealed class PInvokeCallbackComparer : IComparer<PInvokeCallback>
Expand Down
Loading