Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 17fcac4

Browse files
authored
Port to release/2.0.0: Fix chained hardware exception handling on Unix (#12344) (#12350)
There is an issue when hardware exception occurs while handling another hardware exception. In such case, the exception unwinding ends up in an infinite loop. It is caused by the kernel reusing the same location for signal handler context. The fix is to use a windows style context local variable in the common_signal_handler that contains the right context - it is the original signal context converted to windows style context. I've also added regression test for the issue.
1 parent 8044d4f commit 17fcac4

File tree

4 files changed

+89
-8
lines changed

4 files changed

+89
-8
lines changed

src/pal/src/exception/seh-unwind.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,13 +266,8 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
266266
// cannot cross on some systems.
267267
if ((void*)curPc == g_SEHProcessExceptionReturnAddress)
268268
{
269-
ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_EXCEPTION_ACTIVE;
270-
271-
#if defined(_AMD64_)
272-
contextFlags |= CONTEXT_XSTATE;
273-
#endif
274-
size_t nativeContext = *(size_t*)(CONTEXTGetFP(context) + g_common_signal_handler_context_locvar_offset);
275-
CONTEXTFromNativeContext((const native_context_t *)nativeContext, context, contextFlags);
269+
CONTEXT* signalContext = (CONTEXT*)(CONTEXTGetFP(context) + g_common_signal_handler_context_locvar_offset);
270+
memcpy_s(context, sizeof(CONTEXT), signalContext, sizeof(CONTEXT));
276271

277272
return TRUE;
278273
}

src/pal/src/exception/signal.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,12 +761,13 @@ __attribute__((noinline))
761761
static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
762762
{
763763
sigset_t signal_set;
764+
CONTEXT signalContextRecord;
764765
CONTEXT *contextRecord;
765766
EXCEPTION_RECORD *exceptionRecord;
766767
native_context_t *ucontext;
767768

768769
ucontext = (native_context_t *)sigcontext;
769-
g_common_signal_handler_context_locvar_offset = (int)((char*)&ucontext - (char*)__builtin_frame_address(0));
770+
g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
770771

771772
AllocateExceptionRecords(&exceptionRecord, &contextRecord);
772773

@@ -809,6 +810,9 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
809810
}
810811

811812
contextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
813+
814+
memcpy_s(&signalContextRecord, sizeof(CONTEXT), contextRecord, sizeof(CONTEXT));
815+
812816
// The exception object takes ownership of the exceptionRecord and contextRecord
813817
PAL_SEHException exception(exceptionRecord, contextRecord);
814818

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<SchemaVersion>2.0</SchemaVersion>
8+
<ProjectGuid>{9CBB2BDE-E9EF-4F0A-840C-0F80380D4513}</ProjectGuid>
9+
<OutputType>Exe</OutputType>
10+
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
11+
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
12+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
13+
<CLRTestKind>BuildAndRun</CLRTestKind>
14+
<CLRTestPriority>1</CLRTestPriority>
15+
</PropertyGroup>
16+
<!-- Default configurations to help VS understand the configurations -->
17+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
18+
</PropertyGroup>
19+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
20+
</PropertyGroup>
21+
<ItemGroup>
22+
<CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
23+
<Visible>False</Visible>
24+
</CodeAnalysisDependentAssemblyPaths>
25+
</ItemGroup>
26+
<ItemGroup>
27+
<!-- Add Compile Object Here -->
28+
<Compile Include="test12224.cs" />
29+
</ItemGroup>
30+
<ItemGroup>
31+
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
32+
</ItemGroup>
33+
<ItemGroup>
34+
<ProjectReference Include="../../../Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
35+
</ItemGroup>
36+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
37+
<PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
38+
</PropertyGroup>
39+
</Project>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
using System;
5+
using System.Threading;
6+
7+
public class Test12224
8+
{
9+
// Regression test for EH getting stuck in an infinite loop when NullReferenceException
10+
// happens inside a handler of another NullReferenceException.
11+
static void ExecuteTest(object context)
12+
{
13+
string s = null;
14+
try
15+
{
16+
try
17+
{
18+
int x = s.Length;
19+
}
20+
catch (NullReferenceException)
21+
{
22+
int x = s.Length;
23+
}
24+
}
25+
catch (NullReferenceException)
26+
{
27+
28+
}
29+
}
30+
31+
public static int Main()
32+
{
33+
Thread thread = new Thread(new ParameterizedThreadStart(Test12224.ExecuteTest));
34+
thread.IsBackground = true;
35+
thread.Start(null);
36+
37+
// Give the thread 30 seconds to complete (it should be immediate). If it fails
38+
// to complete within that timeout, it has hung.
39+
bool terminated = thread.Join(new TimeSpan(0, 0, 30));
40+
41+
return terminated ? 100 : -1;
42+
}
43+
}

0 commit comments

Comments
 (0)