diff --git a/src/installer/tests/Assets/Projects/AppWithCustomEntryPoints/AppWithCustomEntryPoints.csproj b/src/installer/tests/Assets/Projects/AppWithCustomEntryPoints/AppWithCustomEntryPoints.csproj
index e71444bd29bbfe..585d09a13a809e 100644
--- a/src/installer/tests/Assets/Projects/AppWithCustomEntryPoints/AppWithCustomEntryPoints.csproj
+++ b/src/installer/tests/Assets/Projects/AppWithCustomEntryPoints/AppWithCustomEntryPoints.csproj
@@ -5,4 +5,8 @@
Exe
+
+
+
+
diff --git a/src/installer/tests/Assets/Projects/AppWithCustomEntryPoints/Program.cs b/src/installer/tests/Assets/Projects/AppWithCustomEntryPoints/Program.cs
index 2fb2088dd9e025..e35d3220d293e5 100644
--- a/src/installer/tests/Assets/Projects/AppWithCustomEntryPoints/Program.cs
+++ b/src/installer/tests/Assets/Projects/AppWithCustomEntryPoints/Program.cs
@@ -53,6 +53,9 @@ public static int ThrowException(IntPtr arg, int size)
{
functionPointerCallCount++;
PrintFunctionPointerCallLog(nameof(ThrowException), arg, size);
+
+ // Disable core dumps - test is intentionally crashing
+ Utilities.CoreDump.Disable();
throw new InvalidOperationException(nameof(ThrowException));
}
diff --git a/src/installer/tests/Assets/Projects/Component/Component.cs b/src/installer/tests/Assets/Projects/Component/Component.cs
index 1216e1ecf43105..974bb2c4b7d708 100644
--- a/src/installer/tests/Assets/Projects/Component/Component.cs
+++ b/src/installer/tests/Assets/Projects/Component/Component.cs
@@ -47,6 +47,9 @@ public static int ThrowException(IntPtr arg, int size)
{
componentCallCount++;
PrintComponentCallLog(nameof(ThrowException), arg, size);
+
+ // Disable core dumps - test is intentionally crashing
+ Utilities.CoreDump.Disable();
throw new InvalidOperationException(nameof(ThrowException));
}
diff --git a/src/installer/tests/Assets/Projects/Component/Component.csproj b/src/installer/tests/Assets/Projects/Component/Component.csproj
index f5256336d20533..d56cb42d7259e5 100644
--- a/src/installer/tests/Assets/Projects/Component/Component.csproj
+++ b/src/installer/tests/Assets/Projects/Component/Component.csproj
@@ -5,4 +5,8 @@
true
+
+
+
+
diff --git a/src/installer/tests/Assets/Projects/CoreDump.cs b/src/installer/tests/Assets/Projects/CoreDump.cs
new file mode 100644
index 00000000000000..9a0013e8b35de7
--- /dev/null
+++ b/src/installer/tests/Assets/Projects/CoreDump.cs
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Utilities
+{
+ public static partial class CoreDump
+ {
+ public static void Disable()
+ {
+ string? envValue = Environment.GetEnvironmentVariable("DOTNET_DbgEnableMiniDump");
+ if (envValue is not null && envValue != "0")
+ throw new InvalidOperationException("DOTNET_DbgEnableMiniDump is set and not 0. Ensure it is unset or set to 0 to disable dumps.");
+
+ envValue = Environment.GetEnvironmentVariable("COMPlus_DbgEnableMiniDump");
+ if (envValue is not null && envValue != "0")
+ throw new InvalidOperationException("COMPlus_DbgEnableMiniDump is set and not 0. Ensure it is unset or set to 0 to disable dumps.");
+
+ if (OperatingSystem.IsLinux())
+ {
+ if (prctl(PR_SET_DUMPABLE, 0) != 0)
+ {
+ throw new InvalidOperationException($"Failed to disable core dump. Error: {Marshal.GetLastPInvokeError()}.");
+ }
+ }
+ else if (OperatingSystem.IsMacOS())
+ {
+ RLimit rlimit = new() { rlim_cur = 0, rlim_max = 0 };
+ if (setrlimit(RLIMIT_CORE, rlimit) != 0)
+ {
+ throw new InvalidOperationException($"Failed to disable core dump. Error: {Marshal.GetLastPInvokeError()}.");
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct RLimit
+ {
+ // These are rlim_t. All macOS platforms we use this on currently define it as unsigned 64-bit
+ public ulong rlim_cur; // Soft limit
+ public ulong rlim_max; // Hard limit
+ }
+
+ // Max core file size
+ private const int RLIMIT_CORE = 4;
+
+ [DllImport("libc", SetLastError = true)]
+ private static extern int setrlimit(int resource, in RLimit rlim);
+
+ // "dumpable" attribute of the calling process
+ private const int PR_SET_DUMPABLE = 4;
+
+ [DllImport("libc", SetLastError = true)]
+ private static extern int prctl(int option, int arg2);
+ }
+}
diff --git a/src/installer/tests/Assets/Projects/HelloWorld/HelloWorld.csproj b/src/installer/tests/Assets/Projects/HelloWorld/HelloWorld.csproj
index 7cb5642833fbc8..a600aa229c5ec8 100644
--- a/src/installer/tests/Assets/Projects/HelloWorld/HelloWorld.csproj
+++ b/src/installer/tests/Assets/Projects/HelloWorld/HelloWorld.csproj
@@ -12,4 +12,8 @@
+
+
+
+
diff --git a/src/installer/tests/Assets/Projects/HelloWorld/Program.cs b/src/installer/tests/Assets/Projects/HelloWorld/Program.cs
index f9a5d9c1c4b09b..60bb05c8b641cf 100644
--- a/src/installer/tests/Assets/Projects/HelloWorld/Program.cs
+++ b/src/installer/tests/Assets/Projects/HelloWorld/Program.cs
@@ -50,6 +50,8 @@ public static void Main(string[] args)
}
break;
case "throw_exception":
+ // Disable core dumps - test is intentionally crashing
+ Utilities.CoreDump.Disable();
throw new Exception("Goodbye World!");
default:
break;
diff --git a/src/installer/tests/Assets/Projects/HelloWorld/SelfContained.csproj b/src/installer/tests/Assets/Projects/HelloWorld/SelfContained.csproj
index a6c6ecf1f50d75..d2014e98987476 100644
--- a/src/installer/tests/Assets/Projects/HelloWorld/SelfContained.csproj
+++ b/src/installer/tests/Assets/Projects/HelloWorld/SelfContained.csproj
@@ -12,4 +12,9 @@
<_SupportedArchitecture Condition="'$(TargetArchitecture)' == 'x64' or '$(TargetArchitecture)' == 'x86' or '$(TargetArchitecture)' == 'arm' or '$(TargetArchitecture)' == 'arm64'">true
$(TargetRid)
+
+
+
+
+
diff --git a/src/installer/tests/HostActivation.Tests/Breadcrumbs.cs b/src/installer/tests/HostActivation.Tests/Breadcrumbs.cs
index 242983ece8dfda..4997a574ad983c 100644
--- a/src/installer/tests/HostActivation.Tests/Breadcrumbs.cs
+++ b/src/installer/tests/HostActivation.Tests/Breadcrumbs.cs
@@ -37,7 +37,8 @@ public void UnhandledException_BreadcrumbThreadDoesNotFinish()
TestContext.BuiltDotNet.Exec(sharedTestState.App.AppDll, "throw_exception")
.EnvironmentVariable(Constants.Breadcrumbs.EnvironmentVariable, sharedTestState.BreadcrumbLocation)
.EnableTracingAndCaptureOutputs()
- .Execute(expectedToFail: true)
+ .DisableDumps() // Expected to throw an exception
+ .Execute()
.Should().Fail()
.And.HaveStdErrContaining("Unhandled exception.")
.And.HaveStdErrContaining("System.Exception: Goodbye World")
diff --git a/src/installer/tests/HostActivation.Tests/DependencyResolution/AdditionalDeps.cs b/src/installer/tests/HostActivation.Tests/DependencyResolution/AdditionalDeps.cs
index ebdd3c3ad719a5..68c87d938ad09c 100644
--- a/src/installer/tests/HostActivation.Tests/DependencyResolution/AdditionalDeps.cs
+++ b/src/installer/tests/HostActivation.Tests/DependencyResolution/AdditionalDeps.cs
@@ -99,7 +99,7 @@ public void DepsFile(bool dependencyExists)
CommandResult result = SharedState.DotNetWithNetCoreApp.Exec(Constants.AdditionalDeps.CommandLineArgument, additionalDepsFile, app.AppDll)
.EnableTracingAndCaptureOutputs()
- .Execute(expectedToFail: !dependencyExists);
+ .Execute();
result.Should().HaveUsedAdditionalDeps(additionalDepsFile);
if (dependencyExists)
@@ -126,7 +126,7 @@ public void InvalidJson()
SharedState.DotNetWithNetCoreApp.Exec(Constants.AdditionalDeps.CommandLineArgument, invalidDepsFile, SharedState.FrameworkReferenceApp.AppDll)
.EnableTracingAndCaptureOutputs()
- .Execute(expectedToFail: true)
+ .Execute()
.Should().Fail()
.And.HaveUsedAdditionalDeps(invalidDepsFile)
.And.HaveStdErrContaining($"Error initializing the dependency resolver: An error occurred while parsing: {invalidDepsFile}");
diff --git a/src/installer/tests/HostActivation.Tests/DotnetArgValidation.cs b/src/installer/tests/HostActivation.Tests/DotnetArgValidation.cs
index 4d5498747ae7ed..18ce6bbf5716fd 100644
--- a/src/installer/tests/HostActivation.Tests/DotnetArgValidation.cs
+++ b/src/installer/tests/HostActivation.Tests/DotnetArgValidation.cs
@@ -25,7 +25,7 @@ public void MuxerExec_MissingAppAssembly_Fails()
TestContext.BuiltDotNet.Exec("exec", assemblyName)
.CaptureStdOut()
.CaptureStdErr()
- .Execute(expectedToFail: true)
+ .Execute()
.Should().Fail()
.And.HaveStdErrContaining($"The application to execute does not exist: '{assemblyName}'");
}
@@ -37,7 +37,7 @@ public void MuxerExec_MissingAppAssembly_BadExtension_Fails()
TestContext.BuiltDotNet.Exec("exec", assemblyName)
.CaptureStdOut()
.CaptureStdErr()
- .Execute(expectedToFail: true)
+ .Execute()
.Should().Fail()
.And.HaveStdErrContaining($"The application to execute does not exist: '{assemblyName}'");
}
@@ -52,7 +52,7 @@ public void MuxerExec_BadExtension_Fails()
TestContext.BuiltDotNet.Exec("exec", assemblyName)
.CaptureStdOut()
.CaptureStdErr()
- .Execute(expectedToFail: true)
+ .Execute()
.Should().Fail()
.And.HaveStdErrContaining($"dotnet exec needs a managed .dll or .exe extension. The application specified was '{assemblyName}'");
}
@@ -63,7 +63,7 @@ public void MissingArgumentValue_Fails()
TestContext.BuiltDotNet.Exec("--fx-version")
.CaptureStdOut()
.CaptureStdErr()
- .Execute(expectedToFail: true)
+ .Execute()
.Should().Fail()
.And.HaveStdErrContaining($"Failed to parse supported options or their values:");
}
@@ -76,7 +76,7 @@ public void InvalidFileOrCommand_NoSDK_ListsPossibleIssues()
.WorkingDirectory(sharedTestState.BaseDirectory.Location)
.CaptureStdOut()
.CaptureStdErr()
- .Execute(expectedToFail: true)
+ .Execute()
.Should().Fail()
.And.HaveStdErrContaining($"The application '{fileName}' does not exist")
.And.FindAnySdk(false);
diff --git a/src/installer/tests/HostActivation.Tests/FrameworkDependentAppLaunch.cs b/src/installer/tests/HostActivation.Tests/FrameworkDependentAppLaunch.cs
index 042a5a14bdb9f7..8ff833604de238 100644
--- a/src/installer/tests/HostActivation.Tests/FrameworkDependentAppLaunch.cs
+++ b/src/installer/tests/HostActivation.Tests/FrameworkDependentAppLaunch.cs
@@ -56,7 +56,7 @@ public void Muxer_AssemblyWithDifferentFileExtension_Fails()
TestContext.BuiltDotNet.Exec(appOtherExt)
.CaptureStdErr()
- .Execute(expectedToFail: true)
+ .Execute()
.Should().Fail()
.And.HaveStdErrContaining($"The application '{appOtherExt}' does not exist or is not a managed .dll or .exe");
}
@@ -143,7 +143,8 @@ public void Muxer_NonAssemblyWithExeExtension()
TestContext.BuiltDotNet.Exec(appExe)
.CaptureStdOut()
.CaptureStdErr()
- .Execute(expectedToFail: true)
+ .DisableDumps() // Expected to throw an exception
+ .Execute()
.Should().Fail()
.And.HaveStdErrContaining("BadImageFormatException");
}
@@ -429,7 +430,7 @@ public void AppHost_CLI_MissingRuntimeFramework_ErrorReportedInStdErr(bool missi
.EnableTracingAndCaptureOutputs()
.DotNetRoot(invalidDotNet.Location)
.MultilevelLookup(false)
- .Execute(expectedToFail: true);
+ .Execute();
result.Should().Fail()
.And.HaveStdErrContaining($"https://aka.ms/dotnet-core-applaunch?{expectedUrlQuery}")
diff --git a/src/installer/tests/HostActivation.Tests/InvalidHost.cs b/src/installer/tests/HostActivation.Tests/InvalidHost.cs
index 46d5125d9944af..d260012b27a892 100644
--- a/src/installer/tests/HostActivation.Tests/InvalidHost.cs
+++ b/src/installer/tests/HostActivation.Tests/InvalidHost.cs
@@ -27,7 +27,7 @@ public void AppHost_NotBound()
CommandResult result = Command.Create(sharedTestState.UnboundAppHost)
.CaptureStdErr()
.CaptureStdOut()
- .Execute(expectedToFail: true);
+ .Execute();
result.Should().Fail()
.And.HaveStdErrContaining("This executable is not bound to a managed DLL to execute.")
@@ -70,7 +70,7 @@ public void DotNet_Renamed()
CommandResult result = Command.Create(sharedTestState.RenamedDotNet)
.CaptureStdErr()
.CaptureStdOut()
- .Execute(expectedToFail: true);
+ .Execute();
result.Should().Fail()
.And.HaveStdErrContaining($"Error: cannot execute dotnet when renamed to {Path.GetFileNameWithoutExtension(sharedTestState.RenamedDotNet)}")
diff --git a/src/installer/tests/HostActivation.Tests/NativeHosting/ApplicationExecution.cs b/src/installer/tests/HostActivation.Tests/NativeHosting/ApplicationExecution.cs
index 85125e81b66ae3..a91cd009aa20c0 100644
--- a/src/installer/tests/HostActivation.Tests/NativeHosting/ApplicationExecution.cs
+++ b/src/installer/tests/HostActivation.Tests/NativeHosting/ApplicationExecution.cs
@@ -53,7 +53,8 @@ public void RunApp_UnhandledException()
};
sharedState.CreateNativeHostCommand(args, sharedState.DotNetRoot)
- .Execute(expectedToFail: true)
+ .DisableDumps() // Expected to throw an exception
+ .Execute()
.Should().Fail()
.And.InitializeContextForApp(app.AppDll)
.And.ExecuteApplicationWithException(sharedState.NativeHostPath, app.AppDll);
diff --git a/src/installer/tests/HostActivation.Tests/NativeHosting/GetFunctionPointer.cs b/src/installer/tests/HostActivation.Tests/NativeHosting/GetFunctionPointer.cs
index 4c99262a548f2f..98eadc0b0769c3 100644
--- a/src/installer/tests/HostActivation.Tests/NativeHosting/GetFunctionPointer.cs
+++ b/src/installer/tests/HostActivation.Tests/NativeHosting/GetFunctionPointer.cs
@@ -205,7 +205,8 @@ public void CallDelegateOnApplicationContext_UnhandledException()
};
sharedState.CreateNativeHostCommand(args, sharedState.DotNetRoot)
- .Execute(expectedToFail: true)
+ .DisableDumps() // Expected to throw an exception
+ .Execute()
.Should().Fail()
.And.InitializeContextForApp(app.AppDll)
.And.ExecuteFunctionPointerWithException(entryPoint, 1);
diff --git a/src/installer/tests/HostActivation.Tests/NativeHosting/LoadAssemblyAndGetFunctionPointer.cs b/src/installer/tests/HostActivation.Tests/NativeHosting/LoadAssemblyAndGetFunctionPointer.cs
index 6f7cae81047915..bb13eeafee1c08 100644
--- a/src/installer/tests/HostActivation.Tests/NativeHosting/LoadAssemblyAndGetFunctionPointer.cs
+++ b/src/installer/tests/HostActivation.Tests/NativeHosting/LoadAssemblyAndGetFunctionPointer.cs
@@ -226,7 +226,8 @@ public void CallDelegateOnComponentContext_UnhandledException()
};
sharedState.CreateNativeHostCommand(args, sharedState.DotNetRoot)
- .Execute(expectedToFail: true)
+ .DisableDumps() // Expected to throw an exception
+ .Execute()
.Should().Fail()
.And.InitializeContextForConfig(component.RuntimeConfigJson)
.And.ExecuteFunctionPointerWithException(entryPoint, 1);
diff --git a/src/installer/tests/HostActivation.Tests/SelfContainedAppLaunch.cs b/src/installer/tests/HostActivation.Tests/SelfContainedAppLaunch.cs
index 6b4859b57be2b1..f421335995f696 100644
--- a/src/installer/tests/HostActivation.Tests/SelfContainedAppLaunch.cs
+++ b/src/installer/tests/HostActivation.Tests/SelfContainedAppLaunch.cs
@@ -151,7 +151,7 @@ public void DotNetRoot_IncorrectLayout_Fails()
Command.Create(appExe)
.EnableTracingAndCaptureOutputs()
.DotNetRoot(app.Location)
- .Execute(expectedToFail: true)
+ .Execute()
.Should().Fail()
.And.HaveUsedDotNetRootInstallLocation(Path.GetFullPath(app.Location), TestContext.BuildRID)
.And.HaveStdErrContaining($"The required library {Binaries.HostFxr.FileName} could not be found.");
diff --git a/src/installer/tests/HostActivation.Tests/StartupHooks.cs b/src/installer/tests/HostActivation.Tests/StartupHooks.cs
index c601e6c8f4f274..f902cdf849d3be 100644
--- a/src/installer/tests/HostActivation.Tests/StartupHooks.cs
+++ b/src/installer/tests/HostActivation.Tests/StartupHooks.cs
@@ -96,7 +96,8 @@ public void Muxer_activation_of_StartupHook_With_Missing_Dependencies_Fails()
.EnvironmentVariable("TEST_STARTUPHOOK_USE_DEPENDENCY", true.ToString())
.CaptureStdOut()
.CaptureStdErr()
- .Execute(expectedToFail: true)
+ .DisableDumps() // Expected to throw an exception
+ .Execute()
.Should().Fail()
.And.HaveStdErrContaining("System.IO.FileNotFoundException: Could not load file or assembly 'SharedLibrary");
}
diff --git a/src/installer/tests/TestUtils/Command.cs b/src/installer/tests/TestUtils/Command.cs
index a72beb04230f2f..416a60dac2bb2a 100644
--- a/src/installer/tests/TestUtils/Command.cs
+++ b/src/installer/tests/TestUtils/Command.cs
@@ -17,6 +17,7 @@ public class Command
private StringWriter _stdOutCapture;
private StringWriter _stdErrCapture;
+ private bool _disableDumps = false;
private bool _running = false;
public Process Process { get; }
@@ -133,6 +134,14 @@ private static bool ShouldUseCmd(string executable)
return false;
}
+ public Command DisableDumps()
+ {
+ _disableDumps = true;
+ RemoveEnvironmentVariable("COMPlus_DbgEnableMiniDump");
+ RemoveEnvironmentVariable("DOTNET_DbgEnableMiniDump");
+ return this;
+ }
+
public Command Environment(IDictionary env)
{
if (env == null)
@@ -153,16 +162,27 @@ public Command Environment(string key, string value)
return this;
}
- public CommandResult Execute([CallerMemberName] string caller = "")
- {
- return Execute(false, caller);
- }
-
public Command Start([CallerMemberName] string caller = "")
{
ThrowIfRunning();
_running = true;
+ if (_disableDumps && (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()))
+ {
+ // Replace double quoted arguments with single quotes.
+ // We only want to replace non-escaped quotes - that is, ones not preceded by a backslash
+ // or preceded by an even number of backslashes.
+ string args = System.Text.RegularExpressions.Regex.Replace(
+ Process.StartInfo.Arguments,
+ @"((?:^|[^\\])(?:\\\\)*)""",
+ m => m.Value.Substring(0, m.Value.Length - 1) + "'"
+ );
+
+ // Explicitly set the core file size to 0 before launching the process in the same shell
+ Process.StartInfo.Arguments = $"-c \"ulimit -c 0 && exec {Process.StartInfo.FileName} {args}\"";
+ Process.StartInfo.FileName = "/bin/sh";
+ }
+
if (Process.StartInfo.RedirectStandardOutput)
{
Process.OutputDataReceived += (sender, args) =>
@@ -245,17 +265,9 @@ public CommandResult WaitForExit(int timeoutMilliseconds = Timeout.Infinite, [Ca
///
/// Execute the command and wait for it to exit.
///
- /// Whether or not the command is expected to fail (non-zero exit code)
/// Result of the command
- public CommandResult Execute(bool expectedToFail, [CallerMemberName] string caller = "")
+ public CommandResult Execute([CallerMemberName] string caller = "")
{
- // Clear out any enabling of dump creation if failure is expected
- if (expectedToFail)
- {
- RemoveEnvironmentVariable("COMPlus_DbgEnableMiniDump");
- RemoveEnvironmentVariable("DOTNET_DbgEnableMiniDump");
- }
-
Start(caller);
return WaitForExit(caller: caller);
}