Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在不同dll里面注入,fix不同Dll里面的函数,当这些函数具有同样参数类型的匿名函数会出现报错 #384

Open
754100802 opened this issue Oct 26, 2022 · 1 comment · May be fixed by #391

Comments

@754100802
Copy link

项目里分了几个dll,对这些dll的函数都进行了配置
在dll A里面对某方法 A进行ifix修复,方法 A里面声明了无参匿名函数,在dll B里面对某方法 B进行ifix修复,方法 B里面也声明了无参匿名函数

先游戏中先调用了方法A后再调用方法B会出现报错,反之也会出现,报错如下:
10:14:13.861 F02286 @t001 Fatal ArgumentException: method arguments are incompatible
IFix.Core.VirtualMachine.Execute (IFix.Core.Instruction* pc, IFix.Core.Value* argumentBase, System.Object[] managedStack, IFix.Core.Value* evaluationStackBase, System.Int32 argsCount, System.Int32 methodIndex, System.Int32 refCount, IFix.Core.Value** topWriteBack) (at <7bfd294e701c4e569265a377b712dfc2>:0)
IFix.Core.VirtualMachine.Execute (System.Int32 methodIndex, IFix.Core.Call& call, System.Int32 argsCount, System.Int32 refCount) (at <7bfd294e701c4e569265a377b712dfc2>:0)
IFix.ILFixDynamicMethodWrapper.__Gen_Wrap_63 (System.Object P0, System.Object P1, System.Object P2) (at <9cadca0bf4564926a0c70bfea602861d>:0)

$M85UYIG 0}YRDAJ~8JBIYJ

检查过后发现了在第一次调用的时候会在IFix.Core.Utils的delegateAdptCache字典里面对方法类型进行缓存,在第二次调用的时候会从缓存里面取出同样类型的methodinfo然后执行Delegate.CreateDelegate(delegateType, obj, method1)就会报错,对应出问题的代码

E@(T)W_KWHRZOBTB )S

追下去发现
在创建delegate的过程中
image
实例类型和方法的声明的类runtimetype不同
@S0TK6M1SNNS9OXI 9OZI0T
最后抛出了异常
8`69B{N4}PR3MB3}2ZDTJNF

所以猜测问题是出现在Utils.TryAdapterToDelegate里,在不同的dll里面调用方法的时候
return method1 == (MethodInfo) null ? (Delegate) null : Delegate.CreateDelegate(delegateType, obj, method1);这句里面的obj的实例是不同的,所以它本身的runtimetype也是不同的,实例类型是ILFixDynamicMethodWrapper。但是缓存methodinfo的时候是按照第一个实例来的,就导致了上面出现的报错信息:
Fatal ArgumentException: method arguments are incompatible

不知猜想是否正确,请问有什么合适的解决方法吗

@oahceh
Copy link

oahceh commented Mar 14, 2023

ILFixDynamicMethodWrapper这个是Patch中动态生成的,每个程序集都会有,这里的这个实例类型虽然都是ILFixDynamicMethodWrapper,但它们属于不同的程序集,只是名字相同而已,可以改一下这里的代码,这个cache加一级程序集级别的缓存就行。

static Dictionary<string, Dictionary<Type, MethodInfo>> delegateAdptCache = new Dictionary<string, Dictionary<Type, MethodInfo>>();

public static Delegate TryAdapterToDelegate(object obj, Type delegateType, string perfix)
{
    MethodInfo method;
    if (!delegateAdptCache.TryGetValue(obj.GetType().Assembly.FullName, out var cache))
    {
        cache = new Dictionary<Type, MethodInfo>();
        delegateAdptCache.Add(obj.GetType().Assembly.FullName, cache);
    }

    if (!cache.TryGetValue(delegateType, out method))
    {
        MethodInfo delegateMethod = delegateType.GetMethod("Invoke");
        var methods = obj.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
        for (int i = 0; i < methods.Length; i++)
        {
            if (methods[i].Name.StartsWith(perfix) && IsAssignable(delegateMethod, methods[i]))
            {
                method = methods[i];
                cache[delegateType] = method;
            }
        }
    }

    if (method == null)
    {
        return null;
    }
    else
    {
        return Delegate.CreateDelegate(delegateType, obj, method);
    }
}

oahceh pushed a commit to oahceh/InjectFix that referenced this issue Mar 14, 2023
@oahceh oahceh mentioned this issue Mar 14, 2023
oahceh added a commit to oahceh/InjectFix that referenced this issue Mar 16, 2023
@oahceh oahceh linked a pull request Mar 16, 2023 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants