Open LucaGabi opened 5 years ago
Confirmed, this does not work either:
Shim.Replace(() => TimeZoneInfo.Local).With(() => TimeZoneInfo.Utc);
It's not completely broken in .NET Core 2.1, but there are some really interesting things specific to the low-level CLR magic that .NET Core has subscribed to, which I think Pose would have to work around in order to keep working the way it does in a ton of cases that don't even appear to be all that complex (on the surface).
I'm not in any way affiliated with this project (it just got linked from a Reddit thread, and I was intrigued), but I think the basic idea would be to maintain a list of methods that are implemented as JIT intrinsics and skip rewriting them unless the user explicitly provided an override.
The below code throws an InvalidProgramException
, which other threads seem to have touched on, but that's not actually the interesting part of it. I've included a Ben.Demystifier-processed stack trace so you can follow along (all links go to dotnet/coreclr as of tag "v2.1.11", in case you want to browse around it more):
System.String
to System.ReadOnlySpan<char>
.InvalidProgramException
was the rewrite of this method.Here's the source code so you can mess around with it:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Pose" Version="1.2.1" />
<PackageReference Include="Ben.Demystifier" Version="0.1.4" />
</ItemGroup>
</Project>
{
"sdk": {
"version": "2.1.604"
}
}
using System;
using System.Diagnostics;
using System.Runtime.ExceptionServices;
using Pose;
class Program
{
static void Main()
{
try
{
// writes my actual local offset:
Console.WriteLine(TimeZoneInfo.Local.BaseUtcOffset);
TimeSpan overriddenOffset = default;
PoseContext.Isolate(() => overriddenOffset = TimeZoneInfo.Local.BaseUtcOffset,
Shim.Replace(() => TimeZoneInfo.Local).With(() => TimeZoneInfo.Utc));
// writes "00:00:00":
Console.WriteLine(overriddenOffset);
// writes my actual local offset again:
Console.WriteLine(TimeZoneInfo.Local.BaseUtcOffset);
// throws an error with the stack trace I'm going to paste:
PoseContext.Isolate(() => Console.WriteLine(TimeZoneInfo.Local.BaseUtcOffset),
Shim.Replace(() => TimeZoneInfo.Local).With(() => TimeZoneInfo.Utc));
}
catch (Exception ex)
{
ExceptionDispatchInfo.Capture(ex.Demystify()).Throw();
}
}
}
Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidProgramException: Common Language Runtime detected an invalid program.
at int dynamic_System.Collections.Generic.GenericEqualityComparer`1[System.String]_LastIndexOf(GenericEqualityComparer<string>, string[], string, int, int)
at int stub_virt_System.Collections.Generic.EqualityComparer`1[System.String]_LastIndexOf(EqualityComparer<string>, string[], string, int, int, RuntimeMethodHandle, RuntimeTypeHandle)
at int dynamic_System.Array_LastIndexOf(string[], string, int, int)
at int stub_System.Array_LastIndexOf(string[], string, int, int, RuntimeMethodHandle, RuntimeTypeHandle)
at int dynamic_System.Collections.Generic.List`1[System.String]_LastIndexOf(List<string>, string, int, int)
at int stub_System.Collections.Generic.List`1[System.String]_LastIndexOf(List<string>, string, int, int, RuntimeMethodHandle, RuntimeTypeHandle)
at int dynamic_System.Collections.Generic.List`1[System.String]_LastIndexOf(List<string>, string)
at int stub_virt_System.Collections.Generic.List`1[System.String]_LastIndexOf(List<string>, string, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.SR_InternalGetResourceString(string)
at string stub_System.SR_InternalGetResourceString(string, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.SR_GetResourceString(string, string)
at string stub_System.SR_GetResourceString(string, string, RuntimeMethodHandle, RuntimeTypeHandle)
at string stub_System.SR_get_Arg_PlatformNotSupported(RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.PlatformNotSupportedException_.ctor(PlatformNotSupportedException)
at PlatformNotSupportedException stub_ctor_System.PlatformNotSupportedException_.ctor(RuntimeMethodHandle, RuntimeTypeHandle)
at Byte& dynamic_Internal.Runtime.CompilerServices.Unsafe_As(ref char)
at Byte& stub_Internal.Runtime.CompilerServices.Unsafe_As(ref char, RuntimeMethodHandle, RuntimeTypeHandle)
at bool dynamic_System.String_EqualsHelper(string, string)
at bool stub_System.String_EqualsHelper(string, string, RuntimeMethodHandle, RuntimeTypeHandle)
at bool stub_System.String_Equals(string, string, RuntimeMethodHandle, RuntimeTypeHandle)
at bool stub_System.String_op_Equality(string, string, RuntimeMethodHandle, RuntimeTypeHandle)
at ResourceSet dynamic_System.Resources.ResourceManager_GetFirstResourceSet(ResourceManager, CultureInfo)
at ResourceSet stub_System.Resources.ResourceManager_GetFirstResourceSet(ResourceManager, CultureInfo, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.Resources.ResourceManager_GetString(ResourceManager, string, CultureInfo)
at string stub_virt_System.Resources.ResourceManager_GetString(ResourceManager, string, CultureInfo, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.SR_InternalGetResourceString(string)
at string stub_System.SR_InternalGetResourceString(string, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.SR_GetResourceString(string, string)
at string stub_System.SR_GetResourceString(string, string, RuntimeMethodHandle, RuntimeTypeHandle)
at string stub_System.SR_get_Arg_PlatformNotSupported(RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.PlatformNotSupportedException_.ctor(PlatformNotSupportedException)
at PlatformNotSupportedException stub_ctor_System.PlatformNotSupportedException_.ctor(RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.ByReference`1[System.Char]_.ctor(ref ByReference<char>, ref char)
at ByReference<char> stub_ctor_System.ByReference`1[System.Char]_.ctor(ref char, RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.ReadOnlySpan`1[System.Char]_.ctor(ref ReadOnlySpan<char>, ref char, int)
at ReadOnlySpan<char> stub_ctor_System.ReadOnlySpan`1[System.Char]_.ctor(ref char, int, RuntimeMethodHandle, RuntimeTypeHandle)
at ReadOnlySpan<char> dynamic_System.String_op_Implicit(string)
at ReadOnlySpan<char> stub_System.String_op_Implicit(string, RuntimeMethodHandle, RuntimeTypeHandle)
at StringBuilder dynamic_System.Globalization.TimeSpanFormat_FormatToBuilder(TimeSpan, ReadOnlySpan<char>, IFormatProvider)
at StringBuilder stub_System.Globalization.TimeSpanFormat_FormatToBuilder(TimeSpan, ReadOnlySpan<char>, IFormatProvider, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.Globalization.TimeSpanFormat_Format(TimeSpan, string, IFormatProvider)
at string stub_System.Globalization.TimeSpanFormat_Format(TimeSpan, string, IFormatProvider, RuntimeMethodHandle, RuntimeTypeHandle)
at string dynamic_System.TimeSpan_ToString(ref TimeSpan, string, IFormatProvider)
at string stub_virt_System.IFormattable_ToString(IFormattable, string, IFormatProvider, RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.IO.TextWriter_WriteLine(TextWriter, object)
at void stub_virt_System.IO.TextWriter_WriteLine(TextWriter, object, RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_System.IO.SyncTextWriter_WriteLine(SyncTextWriter, object)
at void stub_virt_System.IO.TextWriter_WriteLine(TextWriter, object, RuntimeMethodHandle, RuntimeTypeHandle)
at void stub_System.Console_WriteLine(object, RuntimeMethodHandle, RuntimeTypeHandle)
at void dynamic_Program+<>c_<Main>b__0_3(?)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at Pose.PoseContext.Isolate(Action entryPoint, Shim[] shims)
at Program.Main() in C:\<SNIP>\Program.cs:line 26
--- End of stack trace from previous location where exception was thrown ---
at Program.Main() in C:\<SNIP>\Program.cs:line 31