diff --git a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs index dd7cd4c6309443..a093940e826a0f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Threading; @@ -318,7 +319,16 @@ private static unsafe uint RunFinalizers() void* fptr = GetNextFinalizeableObject(ObjectHandleOnStack.Create(ref target)); if (fptr == null) break; - ((delegate*)fptr)(target!); + + try + { + ((delegate*)fptr)(target!); + } + catch (Exception ex) when (ExceptionHandling.s_handler?.Invoke(ex) == true) + { + // the handler returned "true" means the exception is now "handled" and we should continue. + } + currentThread.ResetFinalizerThread(); count++; } diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/__Finalizer.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/__Finalizer.cs index 80576c921f8a20..7e9f62d0829da9 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/__Finalizer.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/__Finalizer.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; // @@ -63,10 +64,17 @@ private static unsafe uint DrainQueue() finalizerCount++; - // Call the finalizer on the current target object. If the finalizer throws we'll fail - // fast via normal Redhawk exception semantics (since we don't attempt to catch - // anything). - ((delegate*)target.GetMethodTable()->FinalizerCode)(target); + try + { + // Call the finalizer on the current target object. + ((delegate*)target.GetMethodTable()->FinalizerCode)(target); + } + // We do not use "?." operator here like in other places. + // It would cause "Predefined type 'System.Nullable`1' is not defined" errors. + catch (Exception ex) when (ExceptionHandling.s_handler != null && ExceptionHandling.s_handler(ex)) + { + // the handler returned "true" means the exception is now "handled" and we should continue. + } } } } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs index 7481f3c96a95b8..0743463c15f133 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Thread.NativeAot.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Runtime; using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; @@ -458,6 +459,10 @@ private static void StartThread(IntPtr parameter) startHelper.Run(); } + catch (Exception ex) when (ExceptionHandling.s_handler?.Invoke(ex) == true) + { + // the handler returned "true" means the exception is now "handled" and we should gracefully exit. + } finally { thread.SetThreadStateBit(ThreadState.Stopped); diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/ExceptionServices/ExceptionHandling.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/ExceptionServices/ExceptionHandling.cs new file mode 100644 index 00000000000000..b9fb60a040fee7 --- /dev/null +++ b/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/ExceptionServices/ExceptionHandling.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading; + +namespace System.Runtime.ExceptionServices +{ + public delegate bool UnhandledExceptionHandler(System.Exception exception); + + public static class ExceptionHandling + { + internal static UnhandledExceptionHandler? s_handler; + } +} diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj b/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj index c6c4b5e7d76890..9d606a6b757115 100644 --- a/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj +++ b/src/coreclr/nativeaot/Test.CoreLib/src/Test.CoreLib.csproj @@ -220,6 +220,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index e6246a6f98107a..e7dadba40a5395 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -2572,6 +2572,9 @@ A resolver is already set for the assembly. + + A handler for unhandled exceptions is already set. + Cannot restore context flow when it is not suppressed. diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 1b6323b940e867..5b7c1ca462ef21 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -917,6 +917,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/ExceptionServices/ExceptionHandling.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/ExceptionServices/ExceptionHandling.cs new file mode 100644 index 00000000000000..8921c18a91fd5e --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/ExceptionServices/ExceptionHandling.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading; + +namespace System.Runtime.ExceptionServices +{ + public delegate bool UnhandledExceptionHandler(System.Exception exception); + + public static class ExceptionHandling + { + internal static UnhandledExceptionHandler? s_handler; + + /// + /// Sets a handler for unhandled exceptions. + /// + /// If handler is null + /// If a handler is already set + public static void SetUnhandledExceptionHandler(UnhandledExceptionHandler handler) + { + ArgumentNullException.ThrowIfNull(handler); + + if (Interlocked.CompareExchange(ref s_handler, handler, null) != null) + { + throw new InvalidOperationException(SR.InvalidOperation_CannotRegisterSecondHandler); + } + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs index 92ea2b5f399bd6..dd2c8798ad149d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; +using System.Runtime.ExceptionServices; using System.Runtime.Versioning; using System.Security.Principal; @@ -69,18 +70,25 @@ private void RunWorker() AutoreleasePool.CreateAutoreleasePool(); #endif - if (start is ThreadStart threadStart) + try { - threadStart(); - } - else - { - ParameterizedThreadStart parameterizedThreadStart = (ParameterizedThreadStart)start; + if (start is ThreadStart threadStart) + { + threadStart(); + } + else + { + ParameterizedThreadStart parameterizedThreadStart = (ParameterizedThreadStart)start; - object? startArg = _startArg; - _startArg = null; + object? startArg = _startArg; + _startArg = null; - parameterizedThreadStart(startArg); + parameterizedThreadStart(startArg); + } + } + catch (Exception ex) when (ExceptionHandling.s_handler?.Invoke(ex) == true) + { + // the handler returned "true" means the exception is now "handled" and we should gracefully exit. } #if FEATURE_OBJCMARSHAL diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs index 69a59198a40f4e..c0f920df84becd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Tracing; using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Threading.Tasks; @@ -1187,12 +1188,21 @@ private static void DispatchWorkItem(object workItem, Thread currentThread) { if (workItem is Task task) { + // Task workitems catch their exceptions for later observation + // We do not need to pass unhandled ones to ExceptionHandling.s_handler task.ExecuteFromThreadPool(currentThread); } else { Debug.Assert(workItem is IThreadPoolWorkItem); - Unsafe.As(workItem).Execute(); + try + { + Unsafe.As(workItem).Execute(); + } + catch (Exception ex) when (ExceptionHandling.s_handler?.Invoke(ex) == true) + { + // the handler returned "true" means the exception is now "handled" and we should continue. + } } } } diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 48bd22c6007aa9..d87a6878836231 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -4,8 +4,6 @@ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ -using System.Numerics; - namespace Microsoft.Win32.SafeHandles { public abstract partial class CriticalHandleMinusOneIsInvalid : System.Runtime.InteropServices.CriticalHandle @@ -2418,8 +2416,8 @@ public DivideByZeroException(string? message, System.Exception? innerException) public static double Clamp(double value, double min, double max) { throw null; } public int CompareTo(double value) { throw null; } public int CompareTo(object? value) { throw null; } - public static TInteger ConvertToInteger(double value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static TInteger ConvertToIntegerNative(double value) where TInteger : System.Numerics.IBinaryInteger { throw null; } + public static TInteger ConvertToInteger(double value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static double CopySign(double value, double sign) { throw null; } public static double Cos(double x) { throw null; } public static double Cosh(double x) { throw null; } @@ -2666,14 +2664,12 @@ protected Enum() { } } public static partial class Environment { - public readonly struct ProcessCpuUsage - { - public System.TimeSpan UserTime { get { throw null; } } - public System.TimeSpan PrivilegedTime { get { throw null; } } - public System.TimeSpan TotalTime { get { throw null; } } - } - public static string CommandLine { get { throw null; } } + [System.Runtime.Versioning.SupportedOSPlatformAttribute("maccatalyst")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + public static System.Environment.ProcessCpuUsage CpuUsage { get { throw null; } } public static string CurrentDirectory { get { throw null; } set { } } public static int CurrentManagedThreadId { get { throw null; } } public static int ExitCode { get { throw null; } set { } } @@ -2686,11 +2682,6 @@ public readonly struct ProcessCpuUsage public static System.OperatingSystem OSVersion { get { throw null; } } public static int ProcessId { get { throw null; } } public static int ProcessorCount { get { throw null; } } - [System.Runtime.Versioning.UnsupportedOSPlatform("ios")] - [System.Runtime.Versioning.UnsupportedOSPlatform("tvos")] - [System.Runtime.Versioning.SupportedOSPlatform("maccatalyst")] - [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] - public static ProcessCpuUsage CpuUsage { get { throw null; } } public static string? ProcessPath { get { throw null; } } public static string StackTrace { get { throw null; } } public static string SystemDirectory { get { throw null; } } @@ -2719,6 +2710,13 @@ public readonly struct ProcessCpuUsage public static string[] GetLogicalDrives() { throw null; } public static void SetEnvironmentVariable(string variable, string? value) { } public static void SetEnvironmentVariable(string variable, string? value, System.EnvironmentVariableTarget target) { } + public readonly partial struct ProcessCpuUsage + { + private readonly int _dummyPrimitive; + public System.TimeSpan PrivilegedTime { get { throw null; } } + public System.TimeSpan TotalTime { get { throw null; } } + public System.TimeSpan UserTime { get { throw null; } } + } public enum SpecialFolder { Desktop = 0, @@ -3150,13 +3148,13 @@ public enum GCNotificationStatus public Guid(string g) { throw null; } [System.CLSCompliantAttribute(false)] public Guid(uint a, ushort b, ushort c, byte d, byte e, byte f, byte g, byte h, byte i, byte j, byte k) { throw null; } - public static Guid AllBitsSet { get { throw null; } } + public static System.Guid AllBitsSet { get { throw null; } } public int Variant { get { throw null; } } public int Version { get { throw null; } } public int CompareTo(System.Guid value) { throw null; } public int CompareTo(object? value) { throw null; } - public static Guid CreateVersion7() { throw null; } - public static Guid CreateVersion7(DateTimeOffset timestamp) { throw null; } + public static System.Guid CreateVersion7() { throw null; } + public static System.Guid CreateVersion7(System.DateTimeOffset timestamp) { throw null; } public bool Equals(System.Guid g) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? o) { throw null; } public override int GetHashCode() { throw null; } @@ -3230,8 +3228,8 @@ public enum GCNotificationStatus public static System.Half Clamp(System.Half value, System.Half min, System.Half max) { throw null; } public int CompareTo(System.Half other) { throw null; } public int CompareTo(object? obj) { throw null; } - public static TInteger ConvertToInteger(System.Half value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static TInteger ConvertToIntegerNative(System.Half value) where TInteger : System.Numerics.IBinaryInteger { throw null; } + public static TInteger ConvertToInteger(System.Half value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static System.Half CopySign(System.Half value, System.Half sign) { throw null; } public static System.Half Cos(System.Half x) { throw null; } public static System.Half Cosh(System.Half x) { throw null; } @@ -4446,12 +4444,12 @@ public static partial class Math public static double Atan2(double y, double x) { throw null; } public static double Atanh(double d) { throw null; } public static long BigMul(int a, int b) { throw null; } - public static Int128 BigMul(long a, long b) { throw null; } + public static System.Int128 BigMul(long a, long b) { throw null; } + public static long BigMul(long a, long b, out long low) { throw null; } [System.CLSCompliantAttribute(false)] public static ulong BigMul(uint a, uint b) { throw null; } [System.CLSCompliantAttribute(false)] - public static UInt128 BigMul(ulong a, ulong b) { throw null; } - public static long BigMul(long a, long b, out long low) { throw null; } + public static System.UInt128 BigMul(ulong a, ulong b) { throw null; } [System.CLSCompliantAttribute(false)] public static ulong BigMul(ulong a, ulong b, out ulong low) { throw null; } public static double BitDecrement(double x) { throw null; } @@ -5363,8 +5361,8 @@ public SerializableAttribute() { } public static float Clamp(float value, float min, float max) { throw null; } public int CompareTo(object? value) { throw null; } public int CompareTo(float value) { throw null; } - public static TInteger ConvertToInteger(float value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static TInteger ConvertToIntegerNative(float value) where TInteger : System.Numerics.IBinaryInteger { throw null; } + public static TInteger ConvertToInteger(float value) where TInteger : System.Numerics.IBinaryInteger { throw null; } public static float CopySign(float value, float sign) { throw null; } public static float Cos(float x) { throw null; } public static float Cosh(float x) { throw null; } @@ -5952,31 +5950,30 @@ protected TimeProvider() { } public readonly partial struct TimeSpan : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.IUtf8SpanFormattable { private readonly int _dummyPrimitive; + public const int HoursPerDay = 24; public static readonly System.TimeSpan MaxValue; + public const long MicrosecondsPerDay = (long)86400000000; + public const long MicrosecondsPerHour = (long)3600000000; + public const long MicrosecondsPerMillisecond = (long)1000; + public const long MicrosecondsPerMinute = (long)60000000; + public const long MicrosecondsPerSecond = (long)1000000; + public const long MillisecondsPerDay = (long)86400000; + public const long MillisecondsPerHour = (long)3600000; + public const long MillisecondsPerMinute = (long)60000; + public const long MillisecondsPerSecond = (long)1000; + public const long MinutesPerDay = (long)1440; + public const long MinutesPerHour = (long)60; public static readonly System.TimeSpan MinValue; public const long NanosecondsPerTick = (long)100; + public const long SecondsPerDay = (long)86400; + public const long SecondsPerHour = (long)3600; + public const long SecondsPerMinute = (long)60; public const long TicksPerDay = (long)864000000000; public const long TicksPerHour = (long)36000000000; public const long TicksPerMicrosecond = (long)10; public const long TicksPerMillisecond = (long)10000; public const long TicksPerMinute = (long)600000000; public const long TicksPerSecond = (long)10000000; - public const long MicrosecondsPerMillisecond = (long)1000; - public const long MicrosecondsPerSecond = (long)1000000; - public const long MicrosecondsPerMinute = (long)60000000; - public const long MicrosecondsPerHour = (long)3600000000; - public const long MicrosecondsPerDay = (long)86400000000; - public const long MillisecondsPerSecond = (long)1000; - public const long MillisecondsPerMinute = (long)60000; - public const long MillisecondsPerHour = (long)3600000; - public const long MillisecondsPerDay = (long)86400000; - public const long SecondsPerMinute = (long)60; - public const long SecondsPerHour = (long)3600; - public const long SecondsPerDay = (long)86400; - public const long MinutesPerHour = (long)60; - public const long MinutesPerDay = (long)1440; - public const int HoursPerDay = 24; - public static readonly System.TimeSpan Zero; public TimeSpan(int hours, int minutes, int seconds) { throw null; } public TimeSpan(int days, int hours, int minutes, int seconds) { throw null; } @@ -6008,22 +6005,22 @@ protected TimeProvider() { } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? value) { throw null; } public bool Equals(System.TimeSpan obj) { throw null; } public static bool Equals(System.TimeSpan t1, System.TimeSpan t2) { throw null; } - public static System.TimeSpan FromDays(int days) { throw null; } - public static System.TimeSpan FromDays(int days, int hours = 0, long minutes = 0, long seconds = 0, long milliseconds = 0, long microseconds = 0) { throw null; } - public static System.TimeSpan FromHours(int hours) { throw null; } - public static System.TimeSpan FromHours(int hours, long minutes = 0, long seconds = 0, long milliseconds = 0, long microseconds = 0) { throw null; } - public static System.TimeSpan FromMinutes(long minutes) { throw null; } - public static System.TimeSpan FromMinutes(long minutes, long seconds = 0, long milliseconds = 0, long microseconds = 0) { throw null; } - public static System.TimeSpan FromSeconds(long seconds) { throw null; } - public static System.TimeSpan FromSeconds(long seconds, long milliseconds = 0, long microseconds = 0) { throw null; } - public static System.TimeSpan FromMilliseconds(long milliseconds, long microseconds = 0) { throw null; } - public static System.TimeSpan FromMicroseconds(long microseconds) { throw null; } public static System.TimeSpan FromDays(double value) { throw null; } + public static System.TimeSpan FromDays(int days) { throw null; } + public static System.TimeSpan FromDays(int days, int hours = 0, long minutes = (long)0, long seconds = (long)0, long milliseconds = (long)0, long microseconds = (long)0) { throw null; } public static System.TimeSpan FromHours(double value) { throw null; } + public static System.TimeSpan FromHours(int hours) { throw null; } + public static System.TimeSpan FromHours(int hours, long minutes = (long)0, long seconds = (long)0, long milliseconds = (long)0, long microseconds = (long)0) { throw null; } public static System.TimeSpan FromMicroseconds(double value) { throw null; } + public static System.TimeSpan FromMicroseconds(long microseconds) { throw null; } public static System.TimeSpan FromMilliseconds(double value) { throw null; } + public static System.TimeSpan FromMilliseconds(long milliseconds, long microseconds = (long)0) { throw null; } public static System.TimeSpan FromMinutes(double value) { throw null; } + public static System.TimeSpan FromMinutes(long minutes) { throw null; } + public static System.TimeSpan FromMinutes(long minutes, long seconds = (long)0, long milliseconds = (long)0, long microseconds = (long)0) { throw null; } public static System.TimeSpan FromSeconds(double value) { throw null; } + public static System.TimeSpan FromSeconds(long seconds) { throw null; } + public static System.TimeSpan FromSeconds(long seconds, long milliseconds = (long)0, long microseconds = (long)0) { throw null; } public static System.TimeSpan FromTicks(long value) { throw null; } public override int GetHashCode() { throw null; } public System.TimeSpan Multiply(double factor) { throw null; } @@ -7268,7 +7265,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) static ulong System.Numerics.INumberBase.One { get { throw null; } } static int System.Numerics.INumberBase.Radix { get { throw null; } } static ulong System.Numerics.INumberBase.Zero { get { throw null; } } - public static UInt128 BigMul(ulong left, ulong right) { throw null; } + public static System.UInt128 BigMul(ulong left, ulong right) { throw null; } public static ulong Clamp(ulong value, ulong min, ulong max) { throw null; } public int CompareTo(object? value) { throw null; } public int CompareTo(ulong value) { throw null; } @@ -7892,7 +7889,7 @@ public static partial class Base64 public static bool IsValid(System.ReadOnlySpan base64Text) { throw null; } public static bool IsValid(System.ReadOnlySpan base64Text, out int decodedLength) { throw null; } } - public static class Base64Url + public static partial class Base64Url { public static byte[] DecodeFromChars(System.ReadOnlySpan source) { throw null; } public static int DecodeFromChars(System.ReadOnlySpan source, System.Span destination) { throw null; } @@ -7910,10 +7907,10 @@ public static class Base64Url public static System.Buffers.OperationStatus EncodeToUtf8(System.ReadOnlySpan source, System.Span destination, out int bytesConsumed, out int bytesWritten, bool isFinalBlock = true) { throw null; } public static int GetEncodedLength(int bytesLength) { throw null; } public static int GetMaxDecodedLength(int base64Length) { throw null; } - public static bool IsValid(System.ReadOnlySpan base64UrlText) { throw null; } - public static bool IsValid(System.ReadOnlySpan base64UrlText, out int decodedLength) { throw null; } public static bool IsValid(System.ReadOnlySpan utf8Base64UrlText) { throw null; } public static bool IsValid(System.ReadOnlySpan utf8Base64UrlText, out int decodedLength) { throw null; } + public static bool IsValid(System.ReadOnlySpan base64UrlText) { throw null; } + public static bool IsValid(System.ReadOnlySpan base64UrlText, out int decodedLength) { throw null; } public static bool TryDecodeFromChars(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } public static bool TryDecodeFromUtf8(System.ReadOnlySpan source, System.Span destination, out int bytesWritten) { throw null; } public static bool TryEncodeToChars(System.ReadOnlySpan source, System.Span destination, out int charsWritten) { throw null; } @@ -8204,7 +8201,7 @@ public partial interface IStructuralEquatable } namespace System.Collections.Generic { - public interface IAlternateEqualityComparer where TAlternate : allows ref struct where T : allows ref struct + public partial interface IAlternateEqualityComparer where TAlternate : allows ref struct where T : allows ref struct { bool Equals(TAlternate alternate, T other); int GetHashCode(TAlternate alternate); @@ -8698,8 +8695,8 @@ public enum DebuggerBrowsableState Collapsed = 2, RootHidden = 3, } - [System.AttributeUsage(System.AttributeTargets.Method)] - public sealed class DebuggerDisableUserUnhandledExceptionsAttribute : System.Attribute + [System.AttributeUsageAttribute(System.AttributeTargets.Method)] + public sealed partial class DebuggerDisableUserUnhandledExceptionsAttribute : System.Attribute { public DebuggerDisableUserUnhandledExceptionsAttribute() { } } @@ -8889,14 +8886,14 @@ public ExperimentalAttribute(string diagnosticId) { } public string DiagnosticId { get { throw null; } } public string? UrlFormat { get { throw null; } set { } } } - [System.AttributeUsageAttribute(System.AttributeTargets.Property, Inherited = false, AllowMultiple = true)] - public sealed class FeatureGuardAttribute : System.Attribute + [System.AttributeUsageAttribute(System.AttributeTargets.Property, Inherited=false, AllowMultiple=true)] + public sealed partial class FeatureGuardAttribute : System.Attribute { public FeatureGuardAttribute(System.Type featureType) { } public System.Type FeatureType { get { throw null; } } } - [System.AttributeUsage(System.AttributeTargets.Property, Inherited = false)] - public sealed class FeatureSwitchDefinitionAttribute : Attribute + [System.AttributeUsageAttribute(System.AttributeTargets.Property, Inherited=false)] + public sealed partial class FeatureSwitchDefinitionAttribute : System.Attribute { public FeatureSwitchDefinitionAttribute(string switchName) { } public string SwitchName { get { throw null; } } @@ -9931,7 +9928,6 @@ protected virtual void FillBuffer(int numBytes) { } public virtual int Read(char[] buffer, int index, int count) { throw null; } public virtual int Read(System.Span buffer) { throw null; } public virtual int Read(System.Span buffer) { throw null; } - public virtual void ReadExactly(System.Span buffer) { throw null; } public int Read7BitEncodedInt() { throw null; } public long Read7BitEncodedInt64() { throw null; } public virtual bool ReadBoolean() { throw null; } @@ -9941,6 +9937,7 @@ protected virtual void FillBuffer(int numBytes) { } public virtual char[] ReadChars(int count) { throw null; } public virtual decimal ReadDecimal() { throw null; } public virtual double ReadDouble() { throw null; } + public virtual void ReadExactly(System.Span buffer) { } public virtual System.Half ReadHalf() { throw null; } public virtual short ReadInt16() { throw null; } public virtual int ReadInt32() { throw null; } @@ -10159,19 +10156,19 @@ public static partial class File public static void AppendAllBytes(string path, byte[] bytes) { } public static void AppendAllBytes(string path, System.ReadOnlySpan bytes) { } public static System.Threading.Tasks.Task AppendAllBytesAsync(string path, byte[] bytes, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public static System.Threading.Tasks.Task AppendAllBytesAsync(string path, System.ReadOnlyMemory bytes, System.Threading.CancellationToken cancellationToken = default) { throw null; } + public static System.Threading.Tasks.Task AppendAllBytesAsync(string path, System.ReadOnlyMemory bytes, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static void AppendAllLines(string path, System.Collections.Generic.IEnumerable contents) { } public static void AppendAllLines(string path, System.Collections.Generic.IEnumerable contents, System.Text.Encoding encoding) { } public static System.Threading.Tasks.Task AppendAllLinesAsync(string path, System.Collections.Generic.IEnumerable contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task AppendAllLinesAsync(string path, System.Collections.Generic.IEnumerable contents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public static void AppendAllText(string path, string? contents) { } - public static void AppendAllText(string path, string? contents, System.Text.Encoding encoding) { } public static void AppendAllText(string path, System.ReadOnlySpan contents) { } public static void AppendAllText(string path, System.ReadOnlySpan contents, System.Text.Encoding encoding) { } + public static void AppendAllText(string path, string? contents) { } + public static void AppendAllText(string path, string? contents, System.Text.Encoding encoding) { } + public static System.Threading.Tasks.Task AppendAllTextAsync(string path, System.ReadOnlyMemory contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task AppendAllTextAsync(string path, System.ReadOnlyMemory contents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task AppendAllTextAsync(string path, string? contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task AppendAllTextAsync(string path, string? contents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public static System.Threading.Tasks.Task AppendAllTextAsync(string path, System.ReadOnlyMemory contents, System.Threading.CancellationToken cancellationToken = default) { throw null; } - public static System.Threading.Tasks.Task AppendAllTextAsync(string path, System.ReadOnlyMemory contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default) { throw null; } public static System.IO.StreamWriter AppendText(string path) { throw null; } public static void Copy(string sourceFileName, string destFileName) { } public static void Copy(string sourceFileName, string destFileName, bool overwrite) { } @@ -10252,21 +10249,21 @@ public static void SetUnixFileMode(string path, System.IO.UnixFileMode mode) { } public static void WriteAllBytes(string path, byte[] bytes) { } public static void WriteAllBytes(string path, System.ReadOnlySpan bytes) { } public static System.Threading.Tasks.Task WriteAllBytesAsync(string path, byte[] bytes, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public static System.Threading.Tasks.Task WriteAllBytesAsync(string path, System.ReadOnlyMemory bytes, System.Threading.CancellationToken cancellationToken = default) { throw null; } + public static System.Threading.Tasks.Task WriteAllBytesAsync(string path, System.ReadOnlyMemory bytes, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static void WriteAllLines(string path, System.Collections.Generic.IEnumerable contents) { } public static void WriteAllLines(string path, System.Collections.Generic.IEnumerable contents, System.Text.Encoding encoding) { } public static void WriteAllLines(string path, string[] contents) { } public static void WriteAllLines(string path, string[] contents, System.Text.Encoding encoding) { } public static System.Threading.Tasks.Task WriteAllLinesAsync(string path, System.Collections.Generic.IEnumerable contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task WriteAllLinesAsync(string path, System.Collections.Generic.IEnumerable contents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public static void WriteAllText(string path, string? contents) { } - public static void WriteAllText(string path, string? contents, System.Text.Encoding encoding) { } public static void WriteAllText(string path, System.ReadOnlySpan contents) { } public static void WriteAllText(string path, System.ReadOnlySpan contents, System.Text.Encoding encoding) { } + public static void WriteAllText(string path, string? contents) { } + public static void WriteAllText(string path, string? contents, System.Text.Encoding encoding) { } + public static System.Threading.Tasks.Task WriteAllTextAsync(string path, System.ReadOnlyMemory contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public static System.Threading.Tasks.Task WriteAllTextAsync(string path, System.ReadOnlyMemory contents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task WriteAllTextAsync(string path, string? contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public static System.Threading.Tasks.Task WriteAllTextAsync(string path, string? contents, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } - public static System.Threading.Tasks.Task WriteAllTextAsync(string path, System.ReadOnlyMemory contents, System.Threading.CancellationToken cancellationToken = default) { throw null; } - public static System.Threading.Tasks.Task WriteAllTextAsync(string path, System.ReadOnlyMemory contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken = default) { throw null; } } [System.FlagsAttribute] public enum FileAccess @@ -11612,7 +11609,7 @@ public virtual void GetObjectData(System.Runtime.Serialization.SerializationInfo [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Types and members the loaded assembly depends on might be removed")] [System.ObsoleteAttribute("ReflectionOnly loading is not supported and throws PlatformNotSupportedException.", DiagnosticId="SYSLIB0018", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] public static System.Reflection.Assembly ReflectionOnlyLoadFrom(string assemblyFile) { throw null; } - public static void SetEntryAssembly(System.Reflection.Assembly? assembly) { throw null; } + public static void SetEntryAssembly(System.Reflection.Assembly? assembly) { } public override string ToString() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Types and members the loaded assembly depends on might be removed")] public static System.Reflection.Assembly UnsafeLoadFrom(string assemblyFile) { throw null; } @@ -13547,13 +13544,13 @@ public sealed partial class NullablePublicOnlyAttribute : System.Attribute public readonly bool IncludesInternals; public NullablePublicOnlyAttribute(bool value) { } } - [System.AttributeUsageAttribute(System.AttributeTargets.Method | System.AttributeTargets.Constructor | System.AttributeTargets.Property, AllowMultiple=false, Inherited=false)] + [System.AttributeUsageAttribute(System.AttributeTargets.Constructor | System.AttributeTargets.Method | System.AttributeTargets.Property, AllowMultiple=false, Inherited=false)] public sealed partial class OverloadResolutionPriorityAttribute : System.Attribute { public OverloadResolutionPriorityAttribute(int priority) { } - public int Priority { get { throw null; } } + public int Priority { get { throw null; } } } - [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] + [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, Inherited=true, AllowMultiple=false)] public sealed partial class ParamCollectionAttribute : System.Attribute { public ParamCollectionAttribute() { } @@ -13632,9 +13629,9 @@ public static partial class RuntimeFeature public const string PortablePdb = "PortablePdb"; public const string UnmanagedSignatureCallingConvention = "UnmanagedSignatureCallingConvention"; public const string VirtualStaticsInInterfaces = "VirtualStaticsInInterfaces"; - [System.Diagnostics.CodeAnalysis.FeatureGuard(typeof(System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute))] + [System.Diagnostics.CodeAnalysis.FeatureGuardAttribute(typeof(System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute))] public static bool IsDynamicCodeCompiled { get { throw null; } } - [System.Diagnostics.CodeAnalysis.FeatureSwitchDefinition("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported")] + [System.Diagnostics.CodeAnalysis.FeatureSwitchDefinitionAttribute("System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported")] public static bool IsDynamicCodeSupported { get { throw null; } } public static bool IsSupported(string feature) { throw null; } } @@ -13944,6 +13941,10 @@ internal ExceptionDispatchInfo() { } [System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute] public static void Throw(System.Exception source) => throw null; } + public static partial class ExceptionHandling + { + public static void SetUnhandledExceptionHandler(System.Runtime.ExceptionServices.UnhandledExceptionHandler handler) { } + } public partial class FirstChanceExceptionEventArgs : System.EventArgs { public FirstChanceExceptionEventArgs(System.Exception exception) { } @@ -13955,6 +13956,7 @@ public sealed partial class HandleProcessCorruptedStateExceptionsAttribute : Sys { public HandleProcessCorruptedStateExceptionsAttribute() { } } + public delegate bool UnhandledExceptionHandler(System.Exception exception); } namespace System.Runtime.InteropServices { @@ -14063,14 +14065,14 @@ public static partial class MemoryMarshal public static System.ReadOnlySpan Cast(System.ReadOnlySpan span) where TFrom : struct where TTo : struct { throw null; } public static System.Span Cast(System.Span span) where TFrom : struct where TTo : struct { throw null; } public static System.Memory CreateFromPinnedArray(T[]? array, int start, int length) { throw null; } + [System.CLSCompliantAttribute(false)] + public unsafe static System.ReadOnlySpan CreateReadOnlySpanFromNullTerminated(byte* value) { throw null; } + [System.CLSCompliantAttribute(false)] + public unsafe static System.ReadOnlySpan CreateReadOnlySpanFromNullTerminated(char* value) { throw null; } public static System.ReadOnlySpan CreateReadOnlySpan(scoped ref readonly T reference, int length) { throw null; } - [System.CLSCompliant(false)] - public static unsafe ReadOnlySpan CreateReadOnlySpanFromNullTerminated(byte* value) { throw null; } - [System.CLSCompliant(false)] - public static unsafe ReadOnlySpan CreateReadOnlySpanFromNullTerminated(char* value) { throw null; } public static System.Span CreateSpan(scoped ref T reference, int length) { throw null; } - public static ref T GetArrayDataReference(T[] array) { throw null; } public static ref byte GetArrayDataReference(System.Array array) { throw null; } + public static ref T GetArrayDataReference(T[] array) { throw null; } public static ref T GetReference(System.ReadOnlySpan span) { throw null; } public static ref T GetReference(System.Span span) { throw null; } public static T Read(System.ReadOnlySpan source) where T : struct { throw null; } @@ -14289,11 +14291,11 @@ public partial struct ManagedToUnmanagedOut { private object _dummy; private int _dummyPrimitive; - public void FromUnmanaged(TUnmanagedElement* unmanaged) { throw null; } - public System.ReadOnlySpan ToManaged() { throw null; } - public System.ReadOnlySpan GetUnmanagedValuesSource(int numElements) { throw null; } + public void Free() { } + public unsafe void FromUnmanaged(TUnmanagedElement* unmanaged) { } public System.Span GetManagedValuesDestination(int numElements) { throw null; } - public void Free() { throw null; } + public System.ReadOnlySpan GetUnmanagedValuesSource(int numElements) { throw null; } + public System.ReadOnlySpan ToManaged() { throw null; } } public static partial class UnmanagedToManagedOut { @@ -14375,6 +14377,13 @@ public readonly partial struct SwiftError public unsafe void* Value { get { throw null; } } } [System.CLSCompliantAttribute(false)] + public readonly partial struct SwiftIndirectResult + { + private readonly int _dummyPrimitive; + public unsafe SwiftIndirectResult(void* value) { throw null; } + public unsafe void* Value { get { throw null; } } + } + [System.CLSCompliantAttribute(false)] public readonly partial struct SwiftSelf { private readonly int _dummyPrimitive; @@ -14384,15 +14393,8 @@ public readonly partial struct SwiftSelf public readonly partial struct SwiftSelf where T: unmanaged { private readonly T _dummyPrimitive; - public unsafe SwiftSelf(T value) { throw null; } - public unsafe T Value { get { throw null; } } - } - [System.CLSCompliantAttribute(false)] - public readonly partial struct SwiftIndirectResult - { - private readonly int _dummyPrimitive; - public unsafe SwiftIndirectResult(void* value) { throw null; } - public unsafe void* Value { get { throw null; } } + public SwiftSelf(T value) { throw null; } + public T Value { get { throw null; } } } } namespace System.Runtime.Remoting @@ -15862,7 +15864,7 @@ public void Wait(System.Threading.CancellationToken cancellationToken) { } public bool Wait(System.TimeSpan timeout) { throw null; } public bool Wait(System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) { throw null; } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] - public static void WaitAll(System.Collections.Generic.IEnumerable tasks, System.Threading.CancellationToken cancellationToken = default) { } + public static void WaitAll(System.Collections.Generic.IEnumerable tasks, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public static void WaitAll(params System.ReadOnlySpan tasks) { } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] @@ -16374,7 +16376,7 @@ public partial class NewsStyleUriParser : System.UriParser { public NewsStyleUriParser() { } } - public partial class Uri : System.IFormattable, System.ISpanFormattable, System.IEquatable, System.Runtime.Serialization.ISerializable + public partial class Uri : System.IEquatable, System.IFormattable, System.ISpanFormattable, System.Runtime.Serialization.ISerializable { public static readonly string SchemeDelimiter; public static readonly string UriSchemeFile; @@ -16435,12 +16437,11 @@ protected virtual void Canonicalize() { } protected virtual void CheckSecurity() { } public static int Compare(System.Uri? uri1, System.Uri? uri2, System.UriComponents partsToCompare, System.UriFormat compareFormat, System.StringComparison comparisonType) { throw null; } public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? comparand) { throw null; } - public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] Uri? other) { throw null; } + public bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] System.Uri? other) { throw null; } [System.ObsoleteAttribute("Uri.Escape has been deprecated and is not supported.")] protected virtual void Escape() { } - public static string EscapeDataString(string stringToEscape) { throw null; } public static string EscapeDataString(System.ReadOnlySpan charsToEscape) { throw null; } - public static bool TryEscapeDataString(System.ReadOnlySpan charsToEscape, System.Span destination, out int charsWritten) { throw null; } + public static string EscapeDataString(string stringToEscape) { throw null; } [System.ObsoleteAttribute("Uri.EscapeString has been deprecated. Use GetComponents() or Uri.EscapeDataString to escape a Uri component or a string.")] protected static string EscapeString(string? str) { throw null; } [System.ObsoleteAttribute("Uri.EscapeUriString can corrupt the Uri string in some cases. Consider using Uri.EscapeDataString for query string components instead.", DiagnosticId="SYSLIB0013", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] @@ -16478,12 +16479,13 @@ void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Ser public static bool TryCreate([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true), System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("Uri", new object[]{ "uriKind"})] string? uriString, System.UriKind uriKind, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Uri? result) { throw null; } public static bool TryCreate(System.Uri? baseUri, string? relativeUri, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Uri? result) { throw null; } public static bool TryCreate(System.Uri? baseUri, System.Uri? relativeUri, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Uri? result) { throw null; } + public static bool TryEscapeDataString(System.ReadOnlySpan charsToEscape, System.Span destination, out int charsWritten) { throw null; } public bool TryFormat(System.Span destination, out int charsWritten) { throw null; } + public static bool TryUnescapeDataString(System.ReadOnlySpan charsToUnescape, System.Span destination, out int charsWritten) { throw null; } [System.ObsoleteAttribute("Uri.Unescape has been deprecated. Use GetComponents() or Uri.UnescapeDataString() to unescape a Uri component or a string.")] protected virtual string Unescape(string path) { throw null; } - public static string UnescapeDataString(string stringToUnescape) { throw null; } public static string UnescapeDataString(System.ReadOnlySpan charsToUnescape) { throw null; } - public static bool TryUnescapeDataString(System.ReadOnlySpan charsToUnescape, System.Span destination, out int charsWritten) { throw null; } + public static string UnescapeDataString(string stringToUnescape) { throw null; } } public partial class UriBuilder { diff --git a/src/tests/Exceptions/ForeignThread/ForeignThreadExceptionsNative.cpp b/src/tests/Exceptions/ForeignThread/ForeignThreadExceptionsNative.cpp index d56d8d597c3f16..09fb4cf97c556b 100644 --- a/src/tests/Exceptions/ForeignThread/ForeignThreadExceptionsNative.cpp +++ b/src/tests/Exceptions/ForeignThread/ForeignThreadExceptionsNative.cpp @@ -13,11 +13,7 @@ #include #endif // _WIN32 -// Work around typedef redefinition: platformdefines.h defines error_t -// as unsigned while it's defined as int in errno.h. -#define error_t error_t_ignore #include -#undef error_t typedef void (*PFNACTION1)(); extern "C" DLL_EXPORT void InvokeCallback(PFNACTION1 callback) diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/CMakeLists.txt b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/CMakeLists.txt new file mode 100644 index 00000000000000..383df78aa99d26 --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/CMakeLists.txt @@ -0,0 +1,20 @@ +project (ForeignThreadRevPInvokeUnhandledNative) + +include_directories(${INC_PLATFORM_DIR}) + +if(CLR_CMAKE_HOST_OSX) + # Enable non-POSIX pthreads APIs, which by default are not included in the pthreads header + add_definitions(-D_DARWIN_C_SOURCE) +endif(CLR_CMAKE_HOST_OSX) + +set(SOURCES ForeignThreadRevPInvokeUnhandledNative.cpp) + +if(NOT CLR_CMAKE_HOST_WIN32) + add_compile_options(-pthread) +endif() + +# add the executable +add_library (ForeignThreadRevPInvokeUnhandledNative SHARED ${SOURCES}) + +# add the install targets +install (TARGETS ForeignThreadRevPInvokeUnhandledNative DESTINATION bin) diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/ForeignThreadRevPInvokeUnhandled.cs b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/ForeignThreadRevPInvokeUnhandled.cs new file mode 100644 index 00000000000000..31fe416519c08d --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/ForeignThreadRevPInvokeUnhandled.cs @@ -0,0 +1,91 @@ +// 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.Threading; +using System.Threading.Tasks; +using System.Runtime.InteropServices; +using Xunit; + +public delegate void MyCallback(); + +public class PInvokeRevPInvokeUnhandled +{ + [DllImport("ForeignThreadRevPInvokeUnhandled")] + public static extern void InvokeCallbackOnNewThread(MyCallback callback); + + [ThreadStatic] + private static Exception lastEx; + private static bool expectUnhandledException = false; + + private static bool Handler(Exception ex) + { + lastEx = ex; + return true; + } + + private static void SetHandler() + { + System.Runtime.ExceptionServices.ExceptionHandling.SetUnhandledExceptionHandler(Handler); + } + + // test-wide setup + static PInvokeRevPInvokeUnhandled() + { + AppDomain.CurrentDomain.UnhandledException += (_, _) => + { + if (expectUnhandledException && + lastEx == null) + { + Environment.Exit(100); + } + }; + + SetHandler(); + } + + public static void RunTest() + { + // sanity check, the handler should be working in a separate thread + Thread th = new Thread(() => + { + try + { + lastEx = null; + throw new Exception("here is an unhandled exception1"); + Assert.Fail(); + } + finally + { + Assert.Equal("here is an unhandled exception1", lastEx.Message); + } + }); + + th.Start(); + th.Join(); + + expectUnhandledException = true; + InvokeCallbackOnNewThread(() => { + try + { + lastEx = null; + throw new Exception("here is an unhandled exception2"); + Assert.Fail(); + } + finally + { + Assert.Null(lastEx); + } + }); + + Assert.Fail(); + } + + public static int Main() + { + RunTest(); + + // should not reach here + return 42; + } +} diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/ForeignThreadRevPInvokeUnhandled.csproj b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/ForeignThreadRevPInvokeUnhandled.csproj new file mode 100644 index 00000000000000..ff750db24d1f97 --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/ForeignThreadRevPInvokeUnhandled.csproj @@ -0,0 +1,16 @@ + + + + true + + false + 0 + true + + + + + + + + diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/ForeignThreadRevPInvokeUnhandledNative.cpp b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/ForeignThreadRevPInvokeUnhandledNative.cpp new file mode 100644 index 00000000000000..09fb4cf97c556b --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/ForeignThreadRevPInvokeUnhandled/ForeignThreadRevPInvokeUnhandledNative.cpp @@ -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. + +#include "stdio.h" +#include + +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable:4265 4577) +#include +#pragma warning(pop) +#else // _WIN32 +#include +#endif // _WIN32 + +#include + +typedef void (*PFNACTION1)(); +extern "C" DLL_EXPORT void InvokeCallback(PFNACTION1 callback) +{ + callback(); +} + +#ifndef _WIN32 +void* InvokeCallbackUnix(void* callback) +{ + InvokeCallback((PFNACTION1)callback); + return NULL; +} + +#define AbortIfFail(st) if (st != 0) abort() + +#endif // !_WIN32 + +extern "C" DLL_EXPORT void InvokeCallbackOnNewThread(PFNACTION1 callback) +{ +#ifdef _WIN32 + std::thread t1(InvokeCallback, callback); + t1.join(); +#else // _WIN32 + // For Unix, we need to use pthreads to create the thread so that we can set its stack size. + // We need to set the stack size due to the very small (80kB) default stack size on MUSL + // based Linux distros. + pthread_attr_t attr; + int st = pthread_attr_init(&attr); + AbortIfFail(st); + + // set stack size to 1.5MB + st = pthread_attr_setstacksize(&attr, 0x180000); + AbortIfFail(st); + + pthread_t t; + st = pthread_create(&t, &attr, InvokeCallbackUnix, (void*)callback); + AbortIfFail(st); + + st = pthread_join(t, NULL); + AbortIfFail(st); +#endif // _WIN32 +} diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerRefuses.cs b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerRefuses.cs new file mode 100644 index 00000000000000..e59f6206bd2818 --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerRefuses.cs @@ -0,0 +1,87 @@ +// 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.Threading; +using System.Threading.Tasks; +using TestLibrary; +using Xunit; + +public class HandlerRefuses +{ + [ThreadStatic] + private static Exception lastEx; + + private static bool shouldReturnFalseFromFilter = false; + private static bool expectUnhandledException = false; + + private static bool Handler(Exception ex) + { + if (shouldReturnFalseFromFilter) + { + return false; + } + + lastEx = ex; + return true; + } + + private static void SetHandler() + { + System.Runtime.ExceptionServices.ExceptionHandling.SetUnhandledExceptionHandler(Handler); + } + + // test-wide setup + static HandlerRefuses() + { + AppDomain.CurrentDomain.UnhandledException += (_, _) => + { + if (expectUnhandledException) + { + Environment.Exit(100); + } + }; + + SetHandler(); + } + + [Fact] + public static void Test1() + { + shouldReturnFalseFromFilter = false; + Thread th = new Thread(() => + { + try + { + lastEx = null; + throw new Exception("here is an unhandled exception1"); + Assert.Fail(); + } + finally + { + Assert.Equal("here is an unhandled exception1", lastEx.Message); + } + }); + + th.Start(); + th.Join(); + + shouldReturnFalseFromFilter = true; + expectUnhandledException = true; + th = new Thread(() => + { + try + { + lastEx = null; + throw new Exception("here is an unhandled exception2"); + Assert.Fail(); + } + finally + { + Assert.Null(lastEx); + } + }); + + th.Start(); + th.Join(); + } +} diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerRefuses.csproj b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerRefuses.csproj new file mode 100644 index 00000000000000..45c8b9fc5d801f --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerRefuses.csproj @@ -0,0 +1,14 @@ + + + + true + true + 0 + + + + + + + + diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerThrows.cs b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerThrows.cs new file mode 100644 index 00000000000000..becf6cdddcb76f --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerThrows.cs @@ -0,0 +1,87 @@ +// 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.Threading; +using System.Threading.Tasks; +using TestLibrary; +using Xunit; + +public class HandlerThrows +{ + [ThreadStatic] + private static Exception lastEx; + + private static bool shouldThrowFromFilter = false; + private static bool expectUnhandledException = false; + + private static bool Handler(Exception ex) + { + if (shouldThrowFromFilter) + { + throw new Exception("hello"); + } + + lastEx = ex; + return true; + } + + private static void SetHandler() + { + System.Runtime.ExceptionServices.ExceptionHandling.SetUnhandledExceptionHandler(Handler); + } + + // test-wide setup + static HandlerThrows() + { + AppDomain.CurrentDomain.UnhandledException += (_, _) => + { + if (expectUnhandledException) + { + Environment.Exit(100); + } + }; + + SetHandler(); + } + + [Fact] + public static void Test1() + { + shouldThrowFromFilter = false; + Thread th = new Thread(() => + { + try + { + lastEx = null; + throw new Exception("here is an unhandled exception1"); + Assert.Fail(); + } + finally + { + Assert.Equal("here is an unhandled exception1", lastEx.Message); + } + }); + + th.Start(); + th.Join(); + + shouldThrowFromFilter = true; + expectUnhandledException = true; + th = new Thread(() => + { + try + { + lastEx = null; + throw new Exception("here is an unhandled exception2"); + Assert.Fail(); + } + finally + { + Assert.Null(lastEx); + } + }); + + th.Start(); + th.Join(); + } +} diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerThrows.csproj b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerThrows.csproj new file mode 100644 index 00000000000000..d54dd8f8803078 --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/HandlerThrows.csproj @@ -0,0 +1,14 @@ + + + + true + true + 0 + + + + + + + + diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/NoEffectInMainThread.cs b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/NoEffectInMainThread.cs new file mode 100644 index 00000000000000..704d1eafe37848 --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/NoEffectInMainThread.cs @@ -0,0 +1,80 @@ +// 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.Threading; +using System.Threading.Tasks; +using TestLibrary; +using Xunit; + +public class NoEffectInMainThread +{ + [ThreadStatic] + private static Exception lastEx; + + private static bool expectUnhandledException = false; + private static bool finallyHasRun = false; + + private static bool Handler(Exception ex) + { + lastEx = ex; + return true; + } + + private static void SetHandler() + { + System.Runtime.ExceptionServices.ExceptionHandling.SetUnhandledExceptionHandler(Handler); + } + + // test-wide setup + static NoEffectInMainThread() + { + AppDomain.CurrentDomain.UnhandledException += (_, _) => + { + if (expectUnhandledException && + lastEx == null && + !finallyHasRun) + { + Environment.Exit(100); + } + }; + + SetHandler(); + } + + public static int Main() + { + // sanity check, the handler should be working in a separate thread + Thread th = new Thread(() => + { + try + { + lastEx = null; + throw new Exception("here is an unhandled exception1"); + Assert.Fail(); + } + finally + { + Assert.Equal("here is an unhandled exception1", lastEx.Message); + } + }); + + th.Start(); + th.Join(); + + + expectUnhandledException = true; + try + { + lastEx = null; + throw new Exception("here is an unhandled exception2"); + Assert.Fail(); + } + finally + { + finallyHasRun = true; + } + + // should not reach here + return 42; + } +} diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/NoEffectInMainThread.csproj b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/NoEffectInMainThread.csproj new file mode 100644 index 00000000000000..dc9caee99bef66 --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/NoEffectInMainThread.csproj @@ -0,0 +1,16 @@ + + + + true + + false + true + 0 + + + + + + + + diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/CMakeLists.txt b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/CMakeLists.txt new file mode 100644 index 00000000000000..2f67cc006442f5 --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/CMakeLists.txt @@ -0,0 +1,20 @@ +project (PInvokeRevPInvokeUnhandledNative) + +include_directories(${INC_PLATFORM_DIR}) + +if(CLR_CMAKE_HOST_OSX) + # Enable non-POSIX pthreads APIs, which by default are not included in the pthreads header + add_definitions(-D_DARWIN_C_SOURCE) +endif(CLR_CMAKE_HOST_OSX) + +set(SOURCES PInvokeRevPInvokeUnhandledNative.cpp) + +if(NOT CLR_CMAKE_HOST_WIN32) + add_compile_options(-pthread) +endif() + +# add the executable +add_library (PInvokeRevPInvokeUnhandledNative SHARED ${SOURCES}) + +# add the install targets +install (TARGETS PInvokeRevPInvokeUnhandledNative DESTINATION bin) diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/PInvokeRevPInvokeUnhandled.cs b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/PInvokeRevPInvokeUnhandled.cs new file mode 100644 index 00000000000000..5a66101d2e7ec8 --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/PInvokeRevPInvokeUnhandled.cs @@ -0,0 +1,91 @@ +// 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.Threading; +using System.Threading.Tasks; +using System.Runtime.InteropServices; +using Xunit; + +public delegate void MyCallback(); + +public class PInvokeRevPInvokeUnhandled +{ + [DllImport("PInvokeRevPInvokeUnhandledNative")] + public static extern void InvokeCallback(MyCallback callback); + + [ThreadStatic] + private static Exception lastEx; + private static bool expectUnhandledException = false; + + private static bool Handler(Exception ex) + { + lastEx = ex; + return true; + } + + private static void SetHandler() + { + System.Runtime.ExceptionServices.ExceptionHandling.SetUnhandledExceptionHandler(Handler); + } + + // test-wide setup + static PInvokeRevPInvokeUnhandled() + { + AppDomain.CurrentDomain.UnhandledException += (_, _) => + { + if (expectUnhandledException && + lastEx == null) + { + Environment.Exit(100); + } + }; + + SetHandler(); + } + + public static void RunTest() + { + // sanity check, the handler should be working in a separate thread + Thread th = new Thread(() => + { + try + { + lastEx = null; + throw new Exception("here is an unhandled exception1"); + Assert.Fail(); + } + finally + { + Assert.Equal("here is an unhandled exception1", lastEx.Message); + } + }); + + th.Start(); + th.Join(); + + expectUnhandledException = true; + InvokeCallback(() => { + try + { + lastEx = null; + throw new Exception("here is an unhandled exception2"); + Assert.Fail(); + } + finally + { + Assert.Null(lastEx); + } + }); + + Assert.Fail(); + } + + public static int Main() + { + RunTest(); + + // should not reach here + return 42; + } +} diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/PInvokeRevPInvokeUnhandled.csproj b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/PInvokeRevPInvokeUnhandled.csproj new file mode 100644 index 00000000000000..3e529b0a6e921a --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/PInvokeRevPInvokeUnhandled.csproj @@ -0,0 +1,16 @@ + + + + true + + false + 0 + true + + + + + + + + diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/PInvokeRevPInvokeUnhandledNative.cpp b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/PInvokeRevPInvokeUnhandledNative.cpp new file mode 100644 index 00000000000000..fa6ef6c050c12d --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/PInvokeRevPInvokeUnhandled/PInvokeRevPInvokeUnhandledNative.cpp @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "stdio.h" +#include +#include + +typedef void (*PFNACTION1)(); +extern "C" DLL_EXPORT void InvokeCallback(PFNACTION1 callback) +{ + callback(); +} + +#ifndef _WIN32 +void* InvokeCallbackUnix(void* callback) +{ + InvokeCallback((PFNACTION1)callback); + return NULL; +} + +#endif // !_WIN32 diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/UnhandledTrivial.cs b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/UnhandledTrivial.cs new file mode 100644 index 00000000000000..b7bb9cd5b65e63 --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/UnhandledTrivial.cs @@ -0,0 +1,179 @@ +// 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.Threading; +using System.Threading.Tasks; +using TestLibrary; +using Xunit; + +public class UnhandledTrivial +{ + [ThreadStatic] + private static Exception lastEx; + + private static bool Handler(Exception ex) + { + lastEx = ex; + return true; + } + + private static void SetHandler() + { + System.Runtime.ExceptionServices.ExceptionHandling.SetUnhandledExceptionHandler(Handler); + } + + // test-wide setup + static UnhandledTrivial() + { + AppDomain.CurrentDomain.UnhandledException += (_, _) => + { + Console.WriteLine(); + Console.WriteLine("====== EXCEPTION WAS UNHANDLED? WE DO NOT EXPECT ANY TRULY UNHANDLED EXCEPTIONS IN THIS TEST! ======"); + Console.WriteLine(); + Environment.Exit(42); + }; + + SetHandler(); + } + + [Fact] + public static void SetTwiceFails() + { + // on the main thread + // (exception does not go to the handler) + try + { + Assert.Null(lastEx); + SetHandler(); + Assert.Fail(); + } + catch (InvalidOperationException ex) + { + } + finally + { + Assert.Null(lastEx); + } + } + + [Fact] + public static void SetNull() + { + try + { + Assert.Null(lastEx); + System.Runtime.ExceptionServices.ExceptionHandling.SetUnhandledExceptionHandler(null); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + } + finally + { + Assert.Null(lastEx); + } + } + + [Fact] + public static void SetTwiceFailsUserThread() + { + // in a user thread + Thread th = new Thread(() => + { + try + { + Assert.Null(lastEx); + SetHandler(); + Assert.Fail(); + } + finally + { + Assert.IsType(lastEx); + } + }); + + th.Start(); + th.Join(); + } + + [Fact] + public static void SetTwiceFailsTPWorkitem() + { + // in a threadpool workitem + ThreadPool.QueueUserWorkItem(_ => + { + try + { + lastEx = null; + SetHandler(); + Assert.Fail(); + } + finally + { + Assert.IsType(lastEx); + } + }); + } + + [Fact] + public static void SetTwiceFailsInTask() + { + // in a task + try + { + Task.Run(() => + { + try + { + lastEx = null; + SetHandler(); + Assert.Fail(); + } + finally + { + // NB: Exception that leaves a Task turns into a Faulted result. + // At the point of task completion it is not yet known + // if exception is unhandled as it can be "observed" and handled later. + Assert.Null(lastEx); + } + }).Wait(); + } + catch (AggregateException ex) + { + Assert.IsType(ex.InnerException); + } + } + + class InFinalizer + { + ~InFinalizer() + { + try + { + lastEx = null; + SetHandler(); + Assert.Fail(); + } + finally + { + Assert.IsType(lastEx); + } + } + } + + [Fact] + public static void SetTwiceFailsInFinalizer() + { + // in a finalizer + for (int i = 0; i < 10; i++) + { + new InFinalizer(); + } + + for (int i = 0; i < 10; i++) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + } +} diff --git a/src/tests/baseservices/exceptions/UnhandledExceptionHandler/UnhandledTrivial.csproj b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/UnhandledTrivial.csproj new file mode 100644 index 00000000000000..7fc18f503043fd --- /dev/null +++ b/src/tests/baseservices/exceptions/UnhandledExceptionHandler/UnhandledTrivial.csproj @@ -0,0 +1,14 @@ + + + + true + true + 0 + + + + + + + + diff --git a/src/tests/baseservices/exceptions/unhandled/foreignunhandled.cpp b/src/tests/baseservices/exceptions/unhandled/foreignunhandled.cpp index d56d8d597c3f16..09fb4cf97c556b 100644 --- a/src/tests/baseservices/exceptions/unhandled/foreignunhandled.cpp +++ b/src/tests/baseservices/exceptions/unhandled/foreignunhandled.cpp @@ -13,11 +13,7 @@ #include #endif // _WIN32 -// Work around typedef redefinition: platformdefines.h defines error_t -// as unsigned while it's defined as int in errno.h. -#define error_t error_t_ignore #include -#undef error_t typedef void (*PFNACTION1)(); extern "C" DLL_EXPORT void InvokeCallback(PFNACTION1 callback) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 09fb7bf06044c9..668df9419560f0 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1922,6 +1922,9 @@ https://github.com/dotnet/runtime/issues/98628 + + NYI on Mono +