pardeike / Harmony

A library for patching, replacing and decorating .NET and Mono methods during runtime
https://www.patreon.com/pardeike
MIT License
5.15k stars 485 forks source link

I try to hook DateTime.UtcNow but it throw exception #611

Closed 651467417 closed 1 month ago

651467417 commented 3 months ago

public static class Program { [HarmonyPrefix] static void PostNow(ref DateTime result) { result += TimeSpan.FromMinutes(10); }

private static int Main(string[] args)
{
    Harmony harmony = new Harmony("com.your.unique.id");
    var dateType = typeof(DateTime);
    var orgGet = AccessTools.PropertyGetter(dateType, "UtcNow");
    var getPost = AccessTools.DeclaredMethod(typeof(Program), nameof(PostNow));
    harmony.Patch(orgGet, postfix: new HarmonyMethod(getPost));

    Console.WriteLine("Hello, World! {0}",DateTime.UtcNow);
    return 0;
}

}

stack trace: System.ArgumentException: The value cannot be an empty string. (Parameter 'className') at System.ArgumentException.ThrowNullOrEmptyException(String argument, String paramName) at System.Reflection.RuntimeModule.GetType(String className, Boolean throwOnError, Boolean ignoreCase) at MonoMod.Utils.ReflectionHelper.<>cDisplayClass20_0.<_ResolveReflection>b16(Module module) at System.Linq.Enumerable.SelectArrayIterator2.MoveNext() at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable1 source, Func2 predicate, Boolean& found) at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable1 source, Func2 predicate) at MonoMod.Utils.ReflectionHelper._ResolveReflection(MemberReference mref, Module[] modules) at MonoMod.Utils.ReflectionHelper.ResolveReflection(TypeReference mref) at MonoMod.Utils._DMDEmit.<>c__DisplayClass5_0.<Generate>b__0(VariableDefinition var) at System.Linq.Enumerable.SelectIListIterator2.Fill(IList1 source, Span1 results, Func2 func) at System.Linq.Enumerable.SelectIListIterator2.ToArray() at MonoMod.Utils._DMDEmit.Generate(DynamicMethodDefinition dmd, MethodBase _mb, ILGenerator il) at MonoMod.Utils.DMDEmitDynamicMethodGenerator.GenerateCore(DynamicMethodDefinition dmd, Object context) at MonoMod.Utils.DMDGenerator1.Generate(DynamicMethodDefinition dmd, Object context) at MonoMod.Utils.DynamicMethodDefinition.Generate(Object context) at MonoMod.Utils.DynamicMethodDefinition.Generate() at HarmonyLib.MethodPatcher.CreateReplacement(Dictionary2& finalInstructions) at HarmonyLib.PatchFunctions.UpdateWrapper(MethodBase original, PatchInfo patchInfo) at HarmonyLib.PatchProcessor.Patch() at HarmonyLib.Harmony.Patch(MethodBase original, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod transpiler, HarmonyMethod finalizer) at Program.Main(String[] args) in C:\Users\ConsoleApp1\Program.cs:line 21

pardeike commented 3 months ago

I need more details. Add Harmony.DEBUG = true at the start and run it once. Then post the resulting harmony.log.txt from your Desktop.

651467417 commented 3 months ago

Harmony id=com.your.unique.id, version=2.3.3.0, location=C:\Users\KURO\Downloads\ConsoleApp1\ConsoleApp1\bin\Debug\net8.0\0Harmony.dll, env/clr=8.0.2, platform=Win32NT

Started from static System.Int32 Program::Main(System.String[] args), location C:\Users\KURO\Downloads\ConsoleApp1\ConsoleApp1\bin\Debug\net8.0\ConsoleApp1.dll

At 2024-05-21 09.34.51

Patch: static System.DateTime System.DateTime::get_UtcNow()

Replacement: static System.DateTime System.DateTime::System.DateTime.get_UtcNow_Patch1()

IL_0000: Local var 0: System.UInt64 IL_0000: Local var 1: System.UInt64 IL_0000: Local var 2: IL_0000: Local var 3: System.DateTime/LeapSecondCache IL_0000: Local var 4: System.UInt64 IL_0000: Local var 5: System.DateTime IL_0000: ldloca 5 (System.DateTime) IL_0004: initobj System.DateTime IL_000A: // start original IL_000A: ldsfld System.LeapSecondCache::s_pfnGetSystemTimeAsFileTime IL_000F: stloc.2 IL_0010: ldloca.s 0 (System.UInt64) IL_0012: conv.u IL_0013: ldloc.2 IL_0014: calli System.Void modopt(System.Runtime.CompilerServices.CallConvSuppressGCTransition) (System.UInt64*) IL_0019: ldloc.0 IL_001A: stloc.1 IL_001B: ldsfld System.Boolean System.LeapSecondCache::s_systemSupportsLeapSeconds IL_0020: brfalse => Label0 IL_0025: ldsfld System.LeapSecondCache System.LeapSecondCache::s_leapSecondCache IL_002A: stloc.3 IL_002B: ldloc.1 IL_002C: ldloc.3 IL_002D: ldfld System.UInt64 System.LeapSecondCache::OSFileTimeTicksAtStartOfValidityWindow IL_0032: sub IL_0033: stloc.s 4 (System.UInt64) IL_0035: ldloc.s 4 (System.UInt64) IL_0037: ldc.i4 -1294967296 IL_003C: conv.u8 IL_003D: bge.un => Label1 IL_0042: ldloc.3 IL_0043: ldfld System.UInt64 System.LeapSecondCache::DotnetDateDataAtStartOfValidityWindow IL_0048: ldloc.s 4 (System.UInt64) IL_004A: add IL_004B: newobj System.Void System.DateTime::.ctor(System.UInt64 dateData) IL_0050: br => Label2 IL_0055: Label1 IL_0055: call static System.DateTime System.DateTime::UpdateLeapSecondCacheAndReturnUtcNow() IL_005A: br => Label3 IL_005F: Label0 IL_005F: ldloc.1 IL_0060: ldc.i8 5116597250427387904 IL_0069: add IL_006A: newobj System.Void System.DateTime::.ctor(System.UInt64 dateData) IL_006F: // end original IL_006F: Label2 IL_006F: Label3 IL_006F: stloc 5 (System.DateTime) IL_0073: ldloca 5 (System.DateTime) IL_0077: call static System.Void Program::PostNow(System.DateTime& __result) IL_007C: ldloc 5 (System.DateTime) IL_0080: ret DONE

here is harmony.log.txt

651467417 commented 3 months ago

it seems var2's type not get. cause utcNow is a unsafe function. #

pardeike commented 3 months ago

If a type cannot be used it usually means that your runtime is missing a dependency. That utcnow is unsafe has nothing to do with your problem. Either way this is not a bug in Harmony.

651467417 commented 3 months ago

thank u