using System.Runtime.CompilerServices;
namespace XFESystem.NativeRuntime.Application;
internal static class RuntimeSelfCheck
{
private sealed class Root(int value) { internal int Value = value; }
[ThreadStatic] private static int token;
[MethodImpl(MethodImplOptions.NoInlining)]
private static WeakReference CreateUnrooted() => new(new Root(23));
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Throw() => throw new InvalidOperationException("Independent runtime check");
private sealed class DisposeFlag : IDisposable
{
internal bool Disposed;
public void Dispose() => Disposed = true;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowThroughFinally(ref int completed)
{
try { Throw(); }
finally { completed = 1; }
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowThroughDispose(DisposeFlag resource)
{
using (resource) Throw();
}
internal static void Run()
{
NativePlatform.Write("XFE_APPLICATION_RUNTIME_CHECK_BEGIN\n");
token = 7;
var table = new ConditionalWeakTable<object, Root>();
object key = new(); table.Add(key, new Root(42));
byte[] bytes = new byte[32768]; bytes[^1] = 211;
var weak = CreateUnrooted();
int caught = 0, finalized = 0;
try { Throw(); }
catch (InvalidOperationException) { caught = 1; }
finally { finalized = 1; }
int unwound = 0;
var disposable = new DisposeFlag();
try { ThrowThroughFinally(ref unwound); }
catch (InvalidOperationException) { }
try { ThrowThroughDispose(disposable); }
catch (InvalidOperationException) { }
if (unwound != 1 || !disposable.Disposed) throw new InvalidOperationException("Native exception unwind skipped cleanup.");
using var ready = new ManualResetEventSlim();
using var done = new ManualResetEventSlim();
Exception? threadError = null;
var worker = new Thread(() =>
{
try
{
token = 19;
byte[] rooted = new byte[32768]; rooted[0] = 37; rooted[^1] = 91;
ready.Set();
while (!done.IsSet)
{
if (token != 19 || rooted[0] != 37 || rooted[^1] != 91)
throw new InvalidOperationException("Thread roots/TLS were corrupted");
Thread.Sleep(1);
}
GC.KeepAlive(rooted);
}
catch (Exception error) { threadError = error; ready.Set(); }
}) { IsBackground = true };
worker.Start();
if (!ready.Wait(10_000)) throw new InvalidOperationException("Native managed thread did not start");
for (int collection = 0; collection < 3; collection++) GC.Collect();
done.Set();
if (!worker.Join(10_000)) throw new InvalidOperationException("Native managed thread did not finish");
if (threadError is not null || token != 7 || bytes[^1] != 211 ||
table.GetValue(key, _ => new Root(-1)).Value != 42 || weak.IsAlive || caught != 1 || finalized != 1)
throw new InvalidOperationException("Microsoft runtime GC/EH/TLS/weak reference check failed", threadError);
GC.KeepAlive(bytes); GC.KeepAlive(key);
NativePlatform.Write("XFE_APPLICATION_RUNTIME_CHECK_OK GC CWT weak_reference threads TLS throw catch finally\n");
}
}
using System.Runtime.CompilerServices;
namespace XFESystem.NativeRuntime.Application;
internal static class RuntimeSelfCheck
{
private sealed class Root(int value) { internal int Value = value; }
[ThreadStatic] private static int token;
[MethodImpl(MethodImplOptions.NoInlining)]
private static WeakReference CreateUnrooted() => new(new Root(23));
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Throw() => throw new InvalidOperationException("Independent runtime check");
private sealed class DisposeFlag : IDisposable
{
internal bool Disposed;
public void Dispose() => Disposed = true;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowThroughFinally(ref int completed)
{
try { Throw(); }
finally { completed = 1; }
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowThroughDispose(DisposeFlag resource)
{
using (resource) Throw();
}
internal static void Run()
{
NativePlatform.Write("XFE_APPLICATION_RUNTIME_CHECK_BEGIN\n");
token = 7;
var table = new ConditionalWeakTable<object, Root>();
object key = new(); table.Add(key, new Root(42));
byte[] bytes = new byte[32768]; bytes[^1] = 211;
var weak = CreateUnrooted();
int caught = 0, finalized = 0;
try { Throw(); }
catch (InvalidOperationException) { caught = 1; }
finally { finalized = 1; }
int unwound = 0;
var disposable = new DisposeFlag();
try { ThrowThroughFinally(ref unwound); }
catch (InvalidOperationException) { }
try { ThrowThroughDispose(disposable); }
catch (InvalidOperationException) { }
if (unwound != 1 || !disposable.Disposed) throw new InvalidOperationException("Native exception unwind skipped cleanup.");
using var ready = new ManualResetEventSlim();
using var done = new ManualResetEventSlim();
Exception? threadError = null;
var worker = new Thread(() =>
{
try
{
token = 19;
byte[] rooted = new byte[32768]; rooted[0] = 37; rooted[^1] = 91;
ready.Set();
while (!done.IsSet)
{
if (token != 19 || rooted[0] != 37 || rooted[^1] != 91)
throw new InvalidOperationException("Thread roots/TLS were corrupted");
Thread.Sleep(1);
}
GC.KeepAlive(rooted);
}
catch (Exception error) { threadError = error; ready.Set(); }
}) { IsBackground = true };
worker.Start();
if (!ready.Wait(10_000)) throw new InvalidOperationException("Native managed thread did not start");
for (int collection = 0; collection < 3; collection++) GC.Collect();
done.Set();
if (!worker.Join(10_000)) throw new InvalidOperationException("Native managed thread did not finish");
if (threadError is not null || token != 7 || bytes[^1] != 211 ||
table.GetValue(key, _ => new Root(-1)).Value != 42 || weak.IsAlive || caught != 1 || finalized != 1)
throw new InvalidOperationException("Microsoft runtime GC/EH/TLS/weak reference check failed", threadError);
GC.KeepAlive(bytes); GC.KeepAlive(key);
NativePlatform.Write("XFE_APPLICATION_RUNTIME_CHECK_OK GC CWT weak_reference threads TLS throw catch finally\n");
}
}