Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unhandled exception when dependency is missing #99117

Merged
merged 1 commit into from
Feb 29, 2024
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
24 changes: 12 additions & 12 deletions src/coreclr/vm/exceptionhandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8204,18 +8204,6 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk

NotifyExceptionPassStarted(pThis, pThread, pExInfo);

if (pFrame == FRAME_TOP)
{
// There are no managed frames on the stack, fail fast and report unhandled exception
LONG disposition = InternalUnhandledExceptionFilter_Worker((EXCEPTION_POINTERS *)&pExInfo->m_ptrs);
#ifdef HOST_WINDOWS
CreateCrashDumpIfEnabled(/* fSOException */ FALSE);
RaiseFailFastException(pExInfo->m_ptrs.ExceptionRecord, NULL, 0);
#else
CrashDumpAndTerminateProcess(pExInfo->m_ExceptionCode);
#endif
}

REGDISPLAY* pRD = &pExInfo->m_regDisplay;
pThread->FillRegDisplay(pRD, pStackwalkCtx);

Expand Down Expand Up @@ -8285,6 +8273,18 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk

*pfIsExceptionIntercepted = CheckExceptionInterception(pThis, pExInfo);
}
else
{
// There are no managed frames on the stack, fail fast and report unhandled exception
LONG disposition = InternalUnhandledExceptionFilter_Worker((EXCEPTION_POINTERS *)&pExInfo->m_ptrs);
#ifdef HOST_WINDOWS
CreateCrashDumpIfEnabled(/* fSOException */ FALSE);
GetThread()->SetThreadStateNC(Thread::TSNC_ProcessedUnhandledException);
RaiseException(pExInfo->m_ExceptionCode, EXCEPTION_NONCONTINUABLE_EXCEPTION, pExInfo->m_ptrs.ExceptionRecord->NumberParameters, pExInfo->m_ptrs.ExceptionRecord->ExceptionInformation);
#else
CrashDumpAndTerminateProcess(pExInfo->m_ExceptionCode);
#endif
}

return result;
}
Expand Down
12 changes: 12 additions & 0 deletions src/tests/baseservices/exceptions/unhandled/dependencytodelete.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace Dependency
{
public class DependencyClass
{
public static void Hello()
{
Console.WriteLine("Hello");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<CLRTestKind>BuildOnly</CLRTestKind>
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<Compile Include="dependencytodelete.cs" />
</ItemGroup>
</Project>
10 changes: 6 additions & 4 deletions src/tests/baseservices/exceptions/unhandled/unhandledTester.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ namespace TestUnhandledExceptionTester
{
public class Program
{
static void RunExternalProcess(string unhandledType)
static void RunExternalProcess(string unhandledType, string assembly)
{
List<string> lines = new List<string>();

Process testProcess = new Process();

testProcess.StartInfo.FileName = Path.Combine(Environment.GetEnvironmentVariable("CORE_ROOT"), "corerun");
testProcess.StartInfo.Arguments = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "unhandled.dll") + " " + unhandledType;
testProcess.StartInfo.Arguments = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), assembly) + " " + unhandledType;
testProcess.StartInfo.RedirectStandardError = true;
// Disable creating dump since the target process is expected to fail with an unhandled exception
testProcess.StartInfo.Environment.Remove("DOTNET_DbgEnableMiniDump");
Expand Down Expand Up @@ -116,8 +116,10 @@ static void RunExternalProcess(string unhandledType)
[Fact]
public static void TestEntryPoint()
{
RunExternalProcess("main");
RunExternalProcess("foreign");
RunExternalProcess("main", "unhandled.dll");
RunExternalProcess("foreign", "unhandled.dll");
File.Delete(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dependencytodelete.dll"));
RunExternalProcess("missingdependency", "unhandledmissingdependency.dll");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,10 @@
<OutputItemType>Content</OutputItemType>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</ProjectReference>
<ProjectReference Include="unhandledmissingdependency.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Content</OutputItemType>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</ProjectReference>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Dependency;

namespace DependencyTest
{
internal class Program
{
static void Main(string[] args)
{
DependencyClass.Hello();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Needs explicit Main to return the proper "unhandled exception" exit code -->
<RequiresProcessIsolation>true</RequiresProcessIsolation>
<ReferenceXUnitWrapperGenerator>false</ReferenceXUnitWrapperGenerator>
<CLRTestKind>BuildOnly</CLRTestKind>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="unhandledmissingdependency.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="dependencytodelete.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
</ItemGroup>
</Project>