pardeike / Harmony

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

Stack corruption when patching a method with a struct return type and a lot of struct type parameters #527

Closed Meigyoku-Thmn closed 1 year ago

Meigyoku-Thmn commented 1 year ago

It seems that Harmony is still not out of the stack corrupting problem even in version 2 when dealing with struct type, I think.

I have a minimal example like this:

using HarmonyLib;
using System.Collections.Generic;
using System.Reflection;

namespace LibHarmonyTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var Harmony = new Harmony("Program");
            new Program().Draw(new object(), new[] { '9' }, new Vector2(), new Vector2(), new Vector2(), new Color());
            Harmony.Patch(typeof(Program).GetMethod("Draw"), new HarmonyMethod(drawPrefix));
            new Program().Draw(new object(), new[] { '9' }, new Vector2(), new Vector2(), new Vector2(), new Color());
        }

        public Vector2 Draw(object sb, char[] str, Vector2 position, Vector2 maxBound, Vector2 scale, Color color)
        {
            AddTex(str[0]);
            return new Vector2();
        }

        Dictionary<char, object> CharTiles = new Dictionary<char, object>();
        unsafe void AddTex(char chr)
        {
            // "this"'s value and "this.CharTitles"'s value are unreadable in Visual Studio's debugger after patching
            if (this.CharTiles.ContainsKey(chr))
                return;
            this.CharTiles.Add(chr, new object());
        }

        static readonly MethodInfo drawPrefix = AccessTools.Method(typeof(Program), nameof(DrawPrefix));
        static bool DrawPrefix(
            object __instance, Vector2 __result, object sb, char[] str, Vector2 position, Vector2 maxBound, Vector2 scale, Color color
        )
        {
            // __instance's value here is unreadable in Visual Studio's debugger
            // other param values seem fine.
            return true;
        }
    }

    struct Vector2
    {
        public float X;
        public float Y;
    }

    struct Color
    {
        uint value;
    }
}

I get an exception at if (this.CharTiles.ContainsKey(chr)) like this:

Managed Debugging Assistant 'FatalExecutionEngineError' : 'The runtime has encountered a fatal error. The address of the error was at 0x717fab4d, on thread 0x1f88. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.'

If commenting out the first new Program().Draw method call in the Main method, then another exception shows up instead:

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

Runtime environment:

pardeike commented 1 year ago

You need to test this with the new alpha of Harmony that contains the refactored backend MonoMod.Core.

Meigyoku-Thmn commented 1 year ago

I tried to use the 2.3.0-alpha.5 version and it worked! Thanks.

pardeike commented 1 year ago

Ping @nike4613 - you guys did good