Open
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模式即可.
线索:
- 在调用 this.MulticastFooArray($ref(this.FooArray)); 时, 有一次对FScriptArray的浅拷贝, 记录下了
this.FooArray
的FScriptArray.Data
- 关键代码:
- 在MulticastFooArray执行期间,
this.FooArray
出现了扩容, 其旧FScriptArray.Data
失效 - 在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