Tencent / UnLua

A feature-rich, easy-learning and highly optimized Lua scripting plugin for UE.
Other
2.25k stars 615 forks source link

Unlua中Delegate指针重用 #217

Open fdcumt opened 4 years ago

fdcumt commented 4 years ago

在DelegateHelp中, 是通过一个全局Map, Delegate指针到DelegateDesc的映射, 来查找对应Delegate的具体类型的.

void FDelegateHelper::PreAdd(FMulticastDelegateType *ScriptDelegate, FMulticastDelegateProperty *Property)
{
    check(ScriptDelegate && Property);
    FMulticastDelegateProperty **PropertyPtr = MulticastDelegate2Property.Find(ScriptDelegate);
    if (!PropertyPtr)
    {
        MulticastDelegate2Property.Add(ScriptDelegate, Property);
    }
}

如果ScriptDelegate在MulticastDelegate2Property中存在, 就不做任何操作. 但是在电脑上(目前在电脑上复现过,手机上不确定,理论上有可能),当UE内存重用(UE是自己进行内存管理的,内存重用发生概率很高.), 指针的值(也就是内存逻辑地址)就很有可能发生重复的情况, 当重复后, 就注册不进去了. 如果原来的类型和新类型一致, 那么不会报错, 如果不一致,就会导致类型错误. 即当两个地址相同,但类型不同的Delegate先后注册的时候, 就会发生错误.

修改方法:去重检测

    if (!PropertyPtr || !*PropertyPtr || (*PropertyPtr)->GetName()!=Property->GetName())
    {
        MulticastDelegate2Property.Add(ScriptDelegate, Property);
    }

理论上FDelegateHelper::PreBind也会遇到同样的问题,但是我这里没有遇到过crash,暂时先不改了.

void FDelegateHelper::PreBind(FScriptDelegate *ScriptDelegate, FDelegateProperty *Property)
{
    check(ScriptDelegate && Property);
    FDelegateProperty **PropertyPtr = Delegate2Property.Find(ScriptDelegate);
    if (!PropertyPtr)
    {
        Delegate2Property.Add(ScriptDelegate, Property);
    }
}
fdcumt commented 4 years ago

这个是UFunction被GC了, 还没查到为啥

kimixuchen commented 3 years ago

ScriptDelegate地址重了,说明前一个内存已经被释放了,此时访问Property可能访问到脏地址。我想有没有办法及时清理掉被释放的ScriptDelegate?