| 
									
										
										
										
											2025-05-17 18:56:46 +08:00
										 |  |  |  | // 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(); | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-05-30 19:06:39 +08:00
										 |  |  |  | ETestCrashType CrashNameToEnum(const FString& CrashName) { | 
					
						
							|  |  |  |  | 	UEnum* CrashEnumPtr = nullptr; | 
					
						
							|  |  |  |  | 	if (!CrashEnumPtr) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		CrashEnumPtr = FindObject<UEnum>(ANY_PACKAGE, TEXT("ETestCrashType"), true); | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-05-17 18:56:46 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-30 19:06:39 +08:00
										 |  |  |  | 	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; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2025-05-17 18:56:46 +08:00
										 |  |  |  | // Called every frame
 | 
					
						
							|  |  |  |  | void ACrashActor::Tick(float DeltaTime) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	Super::Tick(DeltaTime); | 
					
						
							| 
									
										
										
										
											2025-05-30 19:06:39 +08:00
										 |  |  |  | 	CrashFrame = 100; | 
					
						
							| 
									
										
										
										
											2025-05-17 18:56:46 +08:00
										 |  |  |  | 	if (Frame++ >= CrashFrame) { | 
					
						
							| 
									
										
										
										
											2025-05-30 19:06:39 +08:00
										 |  |  |  | 		UE_LOG(LogTemp, Error, TEXT("ACrashActor:BeforeCrash")); | 
					
						
							|  |  |  |  | 		CrashTest("CrashOOM"); | 
					
						
							|  |  |  |  | 		//TestCrash(CrashFrame);
 | 
					
						
							| 
									
										
										
										
											2025-05-17 18:56:46 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | } |