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

NullReferenceException on adding postfix #103

Closed dymanoid closed 6 years ago

dymanoid commented 6 years ago

Harmony version 1.1.0.

I'm adding a patch for a method in the Cities:Skylines game. For a particular method, on trying to add a postfix, I get a NRE:

System.NullReferenceException: Object reference not set to an instance of an object
  at Harmony.MethodPatcher.EmitCallParameter (System.Reflection.Emit.ILGenerator il, System.Reflection.MethodBase original, System.Reflection.MethodInfo patch, System.Collections.Generic.Dictionary`2 variables, Boolean allowFirsParamPassthrough)
  at Harmony.MethodPatcher+<>c__DisplayClass18_0.<AddPostfixes>b__1 (System.Reflection.MethodInfo fix)
  at Harmony.CollectionExtensions.Do[MethodInfo] (IEnumerable`1 sequence, System.Action`1 action)
  at Harmony.MethodPatcher.AddPostfixes (System.Reflection.Emit.ILGenerator il, System.Reflection.MethodBase original, System.Collections.Generic.List`1 postfixes, System.Collections.Generic.Dictionary`2 variables, Boolean passthroughPatches)
  at Harmony.MethodPatcher.CreatePatchedMethod (System.Reflection.MethodBase original, System.String harmonyInstanceID, System.Collections.Generic.List`1 prefixes, System.Collections.Generic.List`1 postfixes, System.Collections.Generic.List`1 transpilers)
  --- End of inner exception stack trace ---
  at Harmony.MethodPatcher.CreatePatchedMethod (System.Reflection.MethodBase original, System.String harmonyInstanceID, System.Collections.Generic.List`1 prefixes, System.Collections.Generic.List`1 postfixes, System.Collections.Generic.List`1 transpilers)
  at Harmony.PatchFunctions.UpdateWrapper(System.Reflection.MethodBase original, Harmony.PatchInfo patchInfo, System.String instanceID)
  at Harmony.PatchProcessor.Patch()
  at Harmony.HarmonyInstance.Patch(System.Reflection.MethodBase original, Harmony.HarmonyMethod prefix, Harmony.HarmonyMethod postfix, Harmony.HarmonyMethod transpiler)

The prefix method parameters include some instance fields (___fieldName), the instance itself (__instance), and the original method's parameters (which are correct).

Original method's signature:

private void BuildLabels(
    PoolList<Vector3> vertices,
    PoolList<int> indices,
    PoolList<Vector2> uvs,
    PoolList<Color32> colors)

Postfix signature:

private static void Postfix(
            UIGraph __instance,
            List<CurveSettings> ___m_Curves,
            Rect ___m_GraphRect,
            UIRenderData ___textRenderData,
            PoolList<Vector3> vertices,
            PoolList<int> indices,
            PoolList<Vector2> uvs,
            PoolList<Color32> colors)
pardeike commented 6 years ago

Which version of Harmony and can you give me more info on the signatures of both, the original and the patch methods?

dymanoid commented 6 years ago

Oh, sorry. I updated the issue with the info you requested.

pardeike commented 6 years ago

Maybe you could help me and use/compile a debug version of Harmony so the stacktrace contains line numbers. Without more info I could only guess since I do not have all the information about all the types and classes involved and the call argument emitter code has lots of use cases that cannot be deduced from your information.

dymanoid commented 6 years ago

I think I spotted the issue. The problem was that the target class has both a field and a property with very similar names, and I accidentally used the property instead of the field.

Nevertheless, my suggestion would be to make the exception message be more helpful at this point. Something like 'field xxx not found' rather than just an anonymous NRE.

pardeike commented 6 years ago

Great work. That’s an easy fix, thank you.

pardeike commented 6 years ago

Fixed in https://github.com/pardeike/Harmony/commit/7e1e5623a1818d309a2946baff6f27359c1b70c8. Please verify.