Skip to content
Merged
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
6 changes: 4 additions & 2 deletions src/Tasks/Microsoft.NET.Build.Tasks/CreateAppHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public class CreateAppHost : TaskBase

public bool EnableMacOSCodeSign { get; set; } = false;

public bool DisableCetCompat { get; set; } = false;

protected override void ExecuteCore()
{
try
Expand All @@ -64,12 +66,12 @@ protected override void ExecuteCore()
appBinaryFilePath: AppBinaryName,
windowsGraphicalUserInterface: isGUI,
assemblyToCopyResourcesFrom: resourcesAssembly,
enableMacOSCodeSign: EnableMacOSCodeSign);
enableMacOSCodeSign: EnableMacOSCodeSign,
disableCetCompat: DisableCetCompat);
return;
}
catch (Exception ex) when (ex is IOException ||
ex is UnauthorizedAccessException ||
ex is HResultException ||
(ex is AggregateException && (ex.InnerException is IOException || ex.InnerException is UnauthorizedAccessException)))
{
if (Retries < 0 || attempts == Retries)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ Copyright (c) .NET Foundation. All rights reserved.
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
EnableMacOSCodeSign="$(_EnableMacOSCodeSign)"
DisableCetCompat="$(_DisableCetCompat)"
/>
</Target>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,7 @@ Copyright (c) .NET Foundation. All rights reserved.
'$(SingleFileHostSourcePath)' != '' and
'$(TargetFrameworkIdentifier)' == '.NETCoreApp' and
$([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), 5.0))">true</_UseSingleFileHostForPublish>
<_DisableCetCompat Condition="'$(CetCompat)' == 'false'">true</_DisableCetCompat>
</PropertyGroup>
</Target>

Expand Down Expand Up @@ -746,6 +747,7 @@ Copyright (c) .NET Foundation. All rights reserved.
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
EnableMacOSCodeSign="$(_EnableMacOSCodeSign)"
DisableCetCompat="$(_DisableCetCompat)"
/>
</Target>

Expand Down
35 changes: 35 additions & 0 deletions test/Microsoft.NET.Build.Tests/AppHostTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,41 @@ public void It_uses_an_apphost_based_on_platform_target(string target)
}
}

[Theory]
[InlineData(null)]
[InlineData(true)]
[InlineData(false)]
public void It_can_disable_cetcompat(bool? cetCompat)
{
string rid = "win-x64"; // CET compat support is currently only on Windows x64
var testProject = new TestProject()
{
Name = "CetCompat",
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
RuntimeIdentifier = rid,
IsExe = true,
};
if (cetCompat.HasValue)
{
testProject.AdditionalProperties.Add("CetCompat", cetCompat.ToString());
}

var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: cetCompat.HasValue ? cetCompat.Value.ToString() : "default");
var buildCommand = new BuildCommand(testAsset);
buildCommand.Execute()
.Should()
.Pass();

var outputDirectory = buildCommand.GetOutputDirectory(runtimeIdentifier: rid);
string apphostPath = Path.Combine(outputDirectory.FullName, $"{testProject.Name}.exe");
bool isCetCompatible = PeReaderUtils.IsCetCompatible(apphostPath);

// CetCompat not set : enabled
// CetCompat = true : enabled
// CetCompat = false : disabled
isCetCompatible.Should().Be(!cetCompat.HasValue || cetCompat.Value);
}

[WindowsOnlyFact]
public void AppHost_contains_resources_from_the_managed_dll()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,43 @@ public void It_runs_single_file_apps(string targetFramework, bool selfContained,
.HaveStdOutContaining("Hello World");
}

[Theory]
[InlineData(null)]
[InlineData(true)]
[InlineData(false)]
public void It_can_disable_cetcompat(bool? cetCompat)
{
string rid = "win-x64"; // CET compat support is currently only on Windows x64
var testProject = new TestProject()
{
Name = "CetCompat",
TargetFrameworks = ToolsetInfo.CurrentTargetFramework,
RuntimeIdentifier = rid,
IsExe = true,
};
if (cetCompat.HasValue)
{
testProject.AdditionalProperties.Add("CetCompat", cetCompat.ToString());
}

var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: cetCompat.HasValue ? cetCompat.Value.ToString() : "default");
var publishCommand = new PublishCommand(testAsset);
publishCommand.Execute(PublishSingleFile)
.Should()
.Pass();

DirectoryInfo publishDir = publishCommand.GetOutputDirectory(
targetFramework: testProject.TargetFrameworks,
runtimeIdentifier: rid);
string singleFilePath = Path.Combine(publishDir.FullName, $"{testProject.Name}.exe");
bool isCetCompatible = PeReaderUtils.IsCetCompatible(singleFilePath);

// CetCompat not set : enabled
// CetCompat = true : enabled
// CetCompat = false : disabled
isCetCompatible.Should().Be(!cetCompat.HasValue || cetCompat.Value);
}

[RequiresMSBuildVersionTheory("16.8.0")]
[InlineData(false)]
[InlineData(true)]
Expand Down
26 changes: 26 additions & 0 deletions test/Microsoft.NET.TestFramework/Utilities/PeReaderUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,32 @@ public static bool IsCrossgened(this PEReader peReader)
return isCrossgened;
}

public static bool IsCetCompatible(string filePath)
{
using (PEReader reader = new PEReader(new FileStream(filePath, FileMode.Open, FileAccess.Read)))
{
foreach (DebugDirectoryEntry entry in reader.ReadDebugDirectory())
{
// https://learn.microsoft.com/windows/win32/debug/pe-format#debug-type
const int IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS = 20;
if ((int)entry.Type != IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS)
continue;

// Get the extended DLL characteristics debug directory entry
PEMemoryBlock data = reader.GetSectionData(entry.DataRelativeVirtualAddress);
ushort dllCharacteristics = data.GetReader().ReadUInt16();

// Check for the CET compat bit
// https://learn.microsoft.com/windows/win32/debug/pe-format#extended-dll-characteristics
const ushort IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT = 0x1;
return (dllCharacteristics & IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT) != 0;
}

// Not marked compatible - no debug directory entry for extended DLL characteristics
return false;
}
}

public static string GetAssemblyAttributeValue(string assemblyPath, string attributeName)
{
if (!File.Exists(assemblyPath))
Expand Down