From a1bf3172b673569a713641b96dcbf5b61675fc31 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 5 Sep 2024 17:58:46 +0200 Subject: [PATCH 1/4] Fix reporting illegal instruction exception The new EH (like NativeAOT) was not recognizing illegal instruction as valid hardware exceptions, so the reported error and stack trace were unusable to determine the error cause. This change adds proper reporting of this hardware exception. Close #107145 --- .../Runtime.Base/src/System/Runtime/ExceptionHandling.cs | 8 ++++++++ .../Runtime.Base/src/System/Runtime/ExceptionIDs.cs | 1 + .../src/System/Runtime/ExceptionIDs.cs | 1 + .../src/System/RuntimeExceptionHelpers.cs | 5 +++++ 4 files changed, 15 insertions(+) diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs index 3443e1bcb711a..aa11879668d71 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs @@ -326,6 +326,9 @@ internal static Exception GetClasslibException(ExceptionIDs id, IntPtr address) ExceptionIDs.NullReference => new NullReferenceException(), ExceptionIDs.OutOfMemory => new OutOfMemoryException(), ExceptionIDs.Overflow => new OverflowException(), +#pragma warning disable CS0618 // ExecutionEngineException is obsolete + ExceptionIDs.IllegalInstruction => new ExecutionEngineException("Illegal instruction"), +#pragma warning restore CS0618 _ => null }; #endif @@ -445,6 +448,7 @@ private enum HwExceptionCode : uint STATUS_DATATYPE_MISALIGNMENT = 0x80000002u, STATUS_ACCESS_VIOLATION = 0xC0000005u, + STATUS_ILLEGAL_INSTRUCTION = 0xC000001Du, STATUS_INTEGER_DIVIDE_BY_ZERO = 0xC0000094u, STATUS_INTEGER_OVERFLOW = 0xC0000095u, } @@ -601,6 +605,10 @@ public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) exceptionId = ExceptionIDs.Overflow; break; + case (uint)HwExceptionCode.STATUS_ILLEGAL_INSTRUCTION: + exceptionId = ExceptionIDs.IllegalInstruction; + break; + default: // We don't wrap SEH exceptions from foreign code like CLR does, so we believe that we // know the complete set of HW faults generated by managed code and do not need to handle diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs index 764bd124d6774..1b0a7585d886a 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs @@ -22,5 +22,6 @@ enum ExceptionIDs DataMisaligned = 10, EntrypointNotFound = 11, AmbiguousImplementation = 12, + IllegalInstruction = 13, } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs index 7fc0ad6a9dfeb..2282f35e6bcae 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs @@ -17,5 +17,6 @@ internal enum ExceptionIDs DataMisaligned = 10, EntrypointNotFound = 11, AmbiguousImplementation = 12, + IllegalInstruction = 13, } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs index 0ed5f375cc27c..8084b9970b12e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs @@ -96,6 +96,11 @@ internal static class RuntimeExceptionHelpers FailFast("Access Violation: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. The application will be terminated since this platform does not support throwing an AccessViolationException."); return null; +#pragma warning disable CS0618 // ExecutionEngineException is obsolete + case ExceptionIDs.IllegalInstruction: + return new ExecutionEngineException("Illegal instruction"); +#pragma warning restore CS0618 + case ExceptionIDs.DataMisaligned: return new DataMisalignedException(); From 69f6a7b925a0fdd2e9a8443d4b54d89b478ae23b Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Mon, 9 Sep 2024 16:08:31 +0200 Subject: [PATCH 2/4] Make the illegal instruction fail fast on NativeAOT. --- .../src/System/RuntimeExceptionHelpers.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs index 8084b9970b12e..eaf16de80869f 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs @@ -96,10 +96,9 @@ internal static class RuntimeExceptionHelpers FailFast("Access Violation: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. The application will be terminated since this platform does not support throwing an AccessViolationException."); return null; -#pragma warning disable CS0618 // ExecutionEngineException is obsolete case ExceptionIDs.IllegalInstruction: - return new ExecutionEngineException("Illegal instruction"); -#pragma warning restore CS0618 + FailFast("Illegal instruction."); + return null; case ExceptionIDs.DataMisaligned: return new DataMisalignedException(); From 7f6a9592b7d3df8d96fd4bbd369e8139a741dfcb Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 20 Sep 2024 00:01:25 +0200 Subject: [PATCH 3/4] Update message and add two more hardware exceptions --- .../src/System/Runtime/ExceptionHandling.cs | 14 +++++++++++++- .../src/System/Runtime/ExceptionIDs.cs | 2 ++ .../src/System/Runtime/ExceptionIDs.cs | 2 ++ .../src/System/RuntimeExceptionHelpers.cs | 10 +++++++++- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs index aa11879668d71..0825fcd81360a 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs @@ -327,7 +327,9 @@ internal static Exception GetClasslibException(ExceptionIDs id, IntPtr address) ExceptionIDs.OutOfMemory => new OutOfMemoryException(), ExceptionIDs.Overflow => new OverflowException(), #pragma warning disable CS0618 // ExecutionEngineException is obsolete - ExceptionIDs.IllegalInstruction => new ExecutionEngineException("Illegal instruction"), + ExceptionIDs.IllegalInstruction => new ExecutionEngineException("Illegal instruction: Attempted to execute an instruction code not defined by the processor."), + ExceptionIDs.PrivilegedInstruction => new ExecutionEngineException("Privileged instruction: Attempted to execute an instruction code that cannot be executed in user mode."); + ExceptionIDs.InPageError => new ExecutionEngineException("In page error: Attempted to access a memory page that is not present, and the system is unable to load the page. For example, this exception might occur if a network connection is lost while running a program over a network."); #pragma warning restore CS0618 _ => null }; @@ -448,9 +450,11 @@ private enum HwExceptionCode : uint STATUS_DATATYPE_MISALIGNMENT = 0x80000002u, STATUS_ACCESS_VIOLATION = 0xC0000005u, + STATUS_IN_PAGE_ERROR = 0xC0000006u, STATUS_ILLEGAL_INSTRUCTION = 0xC000001Du, STATUS_INTEGER_DIVIDE_BY_ZERO = 0xC0000094u, STATUS_INTEGER_OVERFLOW = 0xC0000095u, + STATUS_PRIVILEGED_INSTRUCTION = 0xC0000096u, } [StructLayout(LayoutKind.Explicit, Size = AsmOffsets.SIZEOF__PAL_LIMITED_CONTEXT)] public struct PAL_LIMITED_CONTEXT @@ -609,6 +613,14 @@ public static void RhThrowHwEx(uint exceptionCode, ref ExInfo exInfo) exceptionId = ExceptionIDs.IllegalInstruction; break; + case (uint)HwExceptionCode.STATUS_IN_PAGE_ERROR: + exceptionId = ExceptionIDs.InPageError; + break; + + case (uint)HwExceptionCode.STATUS_PRIVILEGED_INSTRUCTION: + exceptionId = ExceptionIDs.PrivilegedInstruction; + break; + default: // We don't wrap SEH exceptions from foreign code like CLR does, so we believe that we // know the complete set of HW faults generated by managed code and do not need to handle diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs index 1b0a7585d886a..85f91f32256bb 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionIDs.cs @@ -23,5 +23,7 @@ enum ExceptionIDs EntrypointNotFound = 11, AmbiguousImplementation = 12, IllegalInstruction = 13, + PrivilegedInstruction = 14, + InPageError = 15, } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs index 2282f35e6bcae..6f9ff82b4fe2c 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ExceptionIDs.cs @@ -18,5 +18,7 @@ internal enum ExceptionIDs EntrypointNotFound = 11, AmbiguousImplementation = 12, IllegalInstruction = 13, + PrivilegedInstruction = 14, + InPageError = 15, } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs index eaf16de80869f..0b994f72e8834 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/RuntimeExceptionHelpers.cs @@ -97,7 +97,15 @@ internal static class RuntimeExceptionHelpers return null; case ExceptionIDs.IllegalInstruction: - FailFast("Illegal instruction."); + FailFast("Illegal instruction: Attempted to execute an instruction code not defined by the processor."); + return null; + + case ExceptionIDs.PrivilegedInstruction: + FailFast("Privileged instruction: Attempted to execute an instruction code that cannot be executed in user mode."); + return null; + + case ExceptionIDs.InPageError: + FailFast("In page error: Attempted to access a memory page that is not present, and the system is unable to load the page. For example, this exception might occur if a network connection is lost while running a program over a network."); return null; case ExceptionIDs.DataMisaligned: From e80673e2873d9e31bb680388b5b50283e1b9b14d Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Fri, 20 Sep 2024 22:55:13 +0200 Subject: [PATCH 4/4] Fix build break --- .../Runtime.Base/src/System/Runtime/ExceptionHandling.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs index 0825fcd81360a..0d81978b677a9 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/ExceptionHandling.cs @@ -328,8 +328,8 @@ internal static Exception GetClasslibException(ExceptionIDs id, IntPtr address) ExceptionIDs.Overflow => new OverflowException(), #pragma warning disable CS0618 // ExecutionEngineException is obsolete ExceptionIDs.IllegalInstruction => new ExecutionEngineException("Illegal instruction: Attempted to execute an instruction code not defined by the processor."), - ExceptionIDs.PrivilegedInstruction => new ExecutionEngineException("Privileged instruction: Attempted to execute an instruction code that cannot be executed in user mode."); - ExceptionIDs.InPageError => new ExecutionEngineException("In page error: Attempted to access a memory page that is not present, and the system is unable to load the page. For example, this exception might occur if a network connection is lost while running a program over a network."); + ExceptionIDs.PrivilegedInstruction => new ExecutionEngineException("Privileged instruction: Attempted to execute an instruction code that cannot be executed in user mode."), + ExceptionIDs.InPageError => new ExecutionEngineException("In page error: Attempted to access a memory page that is not present, and the system is unable to load the page. For example, this exception might occur if a network connection is lost while running a program over a network."), #pragma warning restore CS0618 _ => null };