127 lines
2.7 KiB
C++
127 lines
2.7 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
||
#include "CrashActor.h"
|
||
DEFINE_LOG_CATEGORY(LogCrash);
|
||
// Sets default values
|
||
ACrashActor::ACrashActor()
|
||
{
|
||
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||
PrimaryActorTick.bCanEverTick = true;
|
||
|
||
}
|
||
|
||
// Called when the game starts or when spawned
|
||
void ACrashActor::BeginPlay()
|
||
{
|
||
Super::BeginPlay();
|
||
|
||
}
|
||
void TestCrash(int CrashFrame) {
|
||
auto FN = [=]() {
|
||
int* ptr = nullptr;
|
||
*ptr = CrashFrame + 6;
|
||
};
|
||
FN();
|
||
}
|
||
ETestCrashType CrashNameToEnum(const FString& CrashName) {
|
||
UEnum* CrashEnumPtr = nullptr;
|
||
if (!CrashEnumPtr)
|
||
{
|
||
CrashEnumPtr = FindObject<UEnum>(ANY_PACKAGE, TEXT("ETestCrashType"), true);
|
||
}
|
||
|
||
if (!CrashEnumPtr)
|
||
{
|
||
return ETestCrashType::NullPointer;
|
||
}
|
||
return static_cast<ETestCrashType>(CrashEnumPtr->GetValueByNameString(CrashName));
|
||
}
|
||
void CrashTest(FString CrashName) {
|
||
ETestCrashType Type = CrashNameToEnum(CrashName);
|
||
switch (Type)
|
||
{
|
||
case ETestCrashType::NullPointer:
|
||
{
|
||
volatile char* ptr = nullptr;
|
||
*ptr += 1;
|
||
}
|
||
break;
|
||
case ETestCrashType::ArrayOutOfBounds:
|
||
{
|
||
TArray<int32> emptyArray;
|
||
emptyArray[0] = 10;
|
||
}
|
||
break;
|
||
case ETestCrashType::BadFunctionPtr:
|
||
{
|
||
void(*funcPointer)() = nullptr;
|
||
funcPointer();
|
||
}
|
||
break;
|
||
case ETestCrashType::IllegalAccess:
|
||
{
|
||
int* addrPtr = reinterpret_cast<int*>(0x12345678);
|
||
*addrPtr = 10;
|
||
}
|
||
break;
|
||
case ETestCrashType::StackOverflow:
|
||
{
|
||
using CrashRecursiveFnType = void (*)(int counter);
|
||
static CrashRecursiveFnType CrashFn;
|
||
CrashFn = [](int counter)
|
||
{
|
||
volatile int data[1024]; // 每次递归分配额外栈空间加速溢出
|
||
UE_LOG(LogTemp, Warning, TEXT("Depth: %d"), counter);
|
||
CrashFn(data[0] + 1); // 无限递归
|
||
};
|
||
CrashFn(1);
|
||
}
|
||
break;
|
||
case ETestCrashType::CrashOOM:
|
||
{
|
||
// 持续分配内存直到崩溃
|
||
TArray<void*> MemoryBlocks;
|
||
while (true)
|
||
{
|
||
// 每次分配 100MB(调整数值适配测试环境)
|
||
void* Block = FMemory::Malloc(100 * 1024 * 1024);
|
||
if (!Block)
|
||
{
|
||
// 分配失败时主动崩溃或记录日志
|
||
UE_LOG(LogTemp, Fatal, TEXT("OOM崩溃触发!"));
|
||
break;
|
||
}
|
||
MemoryBlocks.Add(Block);
|
||
}
|
||
}
|
||
break;
|
||
case ETestCrashType::Assert:
|
||
{
|
||
char* assertPtr = nullptr;
|
||
check(assertPtr != nullptr);
|
||
}
|
||
break;
|
||
case ETestCrashType::Ensure:
|
||
{
|
||
char* ensurePtr = nullptr;
|
||
ensure(ensurePtr != nullptr);
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
UE_LOG(LogTemp, Warning, TEXT("Uknown app termination type!"));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
// Called every frame
|
||
void ACrashActor::Tick(float DeltaTime)
|
||
{
|
||
Super::Tick(DeltaTime);
|
||
CrashFrame = 100;
|
||
if (Frame++ >= CrashFrame) {
|
||
UE_LOG(LogTemp, Error, TEXT("ACrashActor:BeforeCrash"));
|
||
CrashTest("CrashOOM");
|
||
//TestCrash(CrashFrame);
|
||
}
|
||
}
|