Skip to content

[UE] Bug: $InRef<UE.TArray>与数组扩容引起的一种崩溃情况 #1963

Open
@mysticfarer

Description

前置阅读 | Pre-reading

Puer的版本 | Puer Version

latest master

UE的版本 | UE Version

5.3 / 5.5

发生在哪个平台 | Platform

Editor(win)

错误信息 | Error Message

此崩溃与函数出参拷贝, 及数组扩容相关,
详见下述 "问题重现".

问题成因虽然比较清楚, 但对如何防止这种情况, 或及时检查到此类问题, 比较困扰,
还请车神指教, 感谢:D

问题重现 | Bug reproduce

[1/5] 打开 puerts_unreal_demo 工程

[2/5] 打开 "继承引擎类功能"

[3/5] 新建 MyPlayerController.ts 文件, 并粘贴下述代码

MyPlayerController.ts

import { $InRef, $Ref, $ref, $unref } from 'puerts';
import * as UE from 'ue';
import { rpc } from 'ue';

class MyPlayerController extends UE.PlayerController
{
    ReceiveBeginPlay(): void
    {
        this.FooArray.Add(11);
        this.FooArray.Add(22);

        this.PrintTArray('MulticastFooArray - Pre: this.FooArray', this.FooArray);
        this.MulticastFooArray($ref(this.FooArray));
        this.PrintTArray('MulticastFooArray - Post: this.FooArray', this.FooArray);
    }

    @rpc.flags(rpc.FunctionFlags.FUNC_Net | rpc.FunctionFlags.FUNC_NetMulticast | rpc.FunctionFlags.FUNC_NetReliable)
    private MulticastFooArray(InArrayRef: $InRef<UE.TArray<number/*@cpp:int*/>>): void
    {
        let InArray = $unref(InArrayRef);
        this.PrintTArray('MulticastFooArray - StepIn: InArray', InArray);
        this.PrintTArray('MulticastFooArray - StepIn: this.FooArray', this.FooArray);

        for (let i = 0; i < 8; ++i)
        {
            this.FooArray.Add(111 + i);
        }
        this.PrintTArray('MulticastFooArray - this.FooArray changed: InArray', InArray);
        this.PrintTArray('MulticastFooArray - this.FooArray changed: this.FooArray', this.FooArray);
    }

    // @no-blueprint
    private PrintTArray(InPrefix: string, InArray: UE.TArray<number>): void
    {
        for (let i = 0; i < InArray.Num(); ++i)
        {
            let n = InArray.Get(i);
            console.log(`${InPrefix}: i=${i}, value=${n}`);
        }
    }

    private FooArray: UE.TArray<number/*@cpp:int*/>;
}

export default MyPlayerController;

[4/5] 修改GameMode, 应用MyPlayerController

[5/5] 在Editor中Play, 即可重现崩溃

无需选择网络模式, 用默认的Standalone模式即可.

线索:

  1. 在调用 this.MulticastFooArray($ref(this.FooArray)); 时, 有一次对FScriptArray的浅拷贝, 记录下了this.FooArrayFScriptArray.Data
  2. 在MulticastFooArray执行期间, this.FooArray出现了扩容, 其旧FScriptArray.Data失效
  3. 在MulticastFooArray执行结束后, 拷贝出参时, 写入了上一步已失效的FScriptArray.Data, 造成内存写越界, 进而在后续环节崩溃

日志:

Puerts: (0x00000559E381C8D0) MulticastFooArray - Pre: this.FooArray: i=0, value=11
Puerts: (0x00000559E381C8D0) MulticastFooArray - Pre: this.FooArray: i=1, value=22

Puerts: (0x00000559E381C8D0) MulticastFooArray - StepIn: InArray: i=0, value=11
Puerts: (0x00000559E381C8D0) MulticastFooArray - StepIn: InArray: i=1, value=22
Puerts: (0x00000559E381C8D0) MulticastFooArray - StepIn: this.FooArray: i=0, value=11
Puerts: (0x00000559E381C8D0) MulticastFooArray - StepIn: this.FooArray: i=1, value=22

Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: InArray: i=0, value=11
Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: InArray: i=1, value=22

Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: this.FooArray: i=0, value=11
Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: this.FooArray: i=1, value=22
Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: this.FooArray: i=2, value=111
Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: this.FooArray: i=3, value=112
Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: this.FooArray: i=4, value=113
Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: this.FooArray: i=5, value=114
Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: this.FooArray: i=6, value=115
Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: this.FooArray: i=7, value=116
Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: this.FooArray: i=8, value=117
Puerts: (0x00000559E381C8D0) MulticastFooArray - this.FooArray changed: this.FooArray: i=9, value=118

Puerts: (0x00000559E381C8D0) MulticastFooArray - Post: this.FooArray: i=0, value=11
Puerts: (0x00000559E381C8D0) MulticastFooArray - Post: this.FooArray: i=1, value=22

Metadata

Assignees

Labels

UnrealbugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions