You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3240806 on 2016/12/20 by John.Barrett Added 'SendUnitRPCChecked' function, to streamline executing 'UnitTestServer_' pseudo-RPC functons within unit tests, on the server. Worked around an Engine bug with NetConnection.QueueBits. Change 3240807 on 2016/12/20 by John.Barrett Added new variations of 'ReceiveNetFieldExports' exploits, "ReceiveNetFieldExports_MapAlloc", "ReceiveNetFieldExports_NullAlloc", "ReceiveNetFieldExports_NullCheck". Change 3241838 on 2016/12/21 by John.Barrett Quick compile fix for Win32. Change 3243149 on 2016/12/22 by John.Barrett Another Win32 compile fix. Change 3252022 on 2017/01/10 by John.Barrett Added new non-shipping commandline switch, for appending to the commandline using a text file: -CmdLineFile="D:\Users\John\Desktop\ServerCmdLine.txt" This sidesteps Windows commandline length limit. Change 3257927 on 2017/01/14 by John.Barrett Fixed a couple of issues in ReceiveNetFieldExports, and deprioritized the remaining issues by only allowing execution when Replay is enabled. #JIRA UENET-460, UENET-466, UENET-472, UENET-478, UENET-484, UENET-490 Change 3258731 on 2017/01/16 by John.Pollard Refactor network actor list management to be more efficient * Move dormancy list management to FNetworkObjectList * Optimize actor network dormancy by removing actors from the active list that are dormant on all connections * Removed NetUpdateTime on actor, and now use the NextUpdateTime on FNetworkObjectInfo (these values are more hot in the cache too) * We now early out of the consider logic faster when possible * Remove other misc unused network state/code and general cleanup Merging using FNMain->DevNetworking Change 3258736 on 2017/01/16 by John.Pollard Fix compile Change 3259482 on 2017/01/16 by John.Pollard Deprecate GetNetworkActor Change 3264957 on 2017/01/19 by John.Pollard Deprecate bPendingNetUpdate, NetUpdateTime and LastNetUpdateTime Merging using FNMain->DevNetworking Change 3264962 on 2017/01/19 by John.Pollard Fix for FORT-35711 - Edited buildings do not always replicate correctly We were removing the actor from the network object list too soon Merging using FNMain->DevNetworking Change 3264963 on 2017/01/19 by John.Pollard Turn on adaptive network updates by default Merging using FNMain->DevNetworking Change 3265878 on 2017/01/20 by John.Pollard UE-40902 - CIS warnings due to deprecated properties Change 3265930 on 2017/01/20 by John.Pollard UE-40902 - CIS warnings due to deprecated properties Change 3273552 on 2017/01/26 by John.Barrett Added way to specify Associativity for binary operators with the expression parser, which defines whether operators of the same precedence are executed Left-To-Right, or Right-To-Left. Defaults to Right-To-Left for legacy reasons. Change 3273553 on 2017/01/26 by John.Barrett Added 'reflect' console command, tying existing FVMReflection helper to a string parser, allowing full access to UE4 reflection using C++ style syntax (like a supercharged get/set command), e.g: "Reflect Find(,PlayerController).Player.ViewportClient.GameInstance.LocalPlayers" Added supporting FVMReflectionParser class, for evaluating strings as reflection statements, using the ExpressionParser code to implement the syntax. Added automation testing for ExpressionParser binary operator Associativity (placed here rather than in Core, as the reflection parser is better suited to associativity tests). Change 3273555 on 2017/01/26 by John.Barrett Added 'ServerAddCardInternal' and 'ServerUndoRemoveCard' exploit unit tests, for testing more nullptr access exploits in the card RPC code. Updated expected results on unit tests for issues that have been fixed. Change 3273931 on 2017/01/26 by Bart.Hawthorne - Steamworks has been upgraded to 1.39 - The steam controller implementation has been rewritten to accommodate the new interface added in 1.36 Change 3275010 on 2017/01/27 by John.Barrett Quick compile fixes. Change 3276218 on 2017/01/27 by John.Pollard FORT-36482 - Fix issue with using wrong serializer for re-mapping objects Merging using FNMain->DevNetworking Change 3276219 on 2017/01/27 by John.Pollard First pass at implementing net relevancy for replays * All connections are considered when determing if an actor is relevant * Enable by setting demo.UseNetRelevancy to 1 * Override cull distance with demo.CullDistanceOverride Merging using FNMain->DevNetworking Change 3278725 on 2017/01/31 by John.Barrett Fixed multiple card system RPC exploits, through checking parameters in _Validate functions. #JIRA UENET-445, UENET-512 and UENET-518 Change 3278730 on 2017/01/31 by John.Barrett Misc. NetcodeUnitTest updates. Change 3278733 on 2017/01/31 by John.Barrett Marked last of card unit tests as fixed. Change 3278956 on 2017/01/31 by Bart.Hawthorne Disable static analysis warnings from Steamworks headers #jira UE-41262 Change 3278978 on 2017/01/31 by Bart.Hawthorne Fixed Linux warning caused by initializing variables out of order #jira UE-41307 Change 3280081 on 2017/01/31 by Bart.Hawthorne ShooterGame now supports dedicated servers on PC/Mac/Linux Change 3281217 on 2017/02/01 by John.Pollard PR #3172 - GitHub 3172 : Fixed IPAddressBSD validation when setting Ip from string. Change 3283556 on 2017/02/02 by John.Barrett CIS compile fixes. Change 3284509 on 2017/02/02 by John.Barrett CIS no-PCH compile fixes. Change 3285075 on 2017/02/03 by Bart.Hawthorne - Use Engine\Binaries\ThirdParty\Steamworks libraries for 64 bit Steam builds since it seems to be working with 1.39 - Add 32 bit and 64 bit Steam libs for linux Change 3285229 on 2017/02/03 by John.Barrett CIS monolithic include warning fixes. Change 3286108 on 2017/02/03 by Bart.Hawthorne - Fixed issues with Steam not working correctly on Linux - Removed unnecessary controller.vdf dependency [CL 3289494 by Ryan Gerleve in Main branch]
623 lines
18 KiB
C++
623 lines
18 KiB
C++
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "TestPALLog.h"
|
|
#include "Parent.h"
|
|
#include "Stats/StatsMisc.h"
|
|
#include "HAL/RunnableThread.h"
|
|
#include "GenericPlatform/GenericApplication.h"
|
|
|
|
#include "TestDirectoryWatcher.h"
|
|
#include "RequiredProgramMainCPPInclude.h"
|
|
#include "MallocPoisonProxy.h"
|
|
|
|
DEFINE_LOG_CATEGORY(LogTestPAL);
|
|
|
|
IMPLEMENT_APPLICATION(TestPAL, "TestPAL");
|
|
|
|
#define ARG_PROC_TEST "proc"
|
|
#define ARG_PROC_TEST_CHILD "proc-child"
|
|
#define ARG_CASE_SENSITIVITY_TEST "case"
|
|
#define ARG_MESSAGEBOX_TEST "messagebox"
|
|
#define ARG_DIRECTORY_WATCHER_TEST "dirwatcher"
|
|
#define ARG_THREAD_SINGLETON_TEST "threadsingleton"
|
|
#define ARG_SYSINFO_TEST "sysinfo"
|
|
#define ARG_CRASH_TEST "crash"
|
|
#define ARG_STRINGPRECISION_TEST "stringprecision"
|
|
#define ARG_DSO_TEST "dso"
|
|
#define ARG_GET_ALLOCATION_SIZE_TEST "getallocationsize"
|
|
|
|
namespace TestPAL
|
|
{
|
|
FString CommandLine;
|
|
};
|
|
|
|
/**
|
|
* FProcHandle test (child instance)
|
|
*/
|
|
int32 ProcRunAsChild(const TCHAR* CommandLine)
|
|
{
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(CommandLine);
|
|
|
|
// set a random delay pretending to do some useful work up to a minute.
|
|
srand(FPlatformProcess::GetCurrentProcessId());
|
|
double RandomWorkTime = FMath::FRandRange(0.0f, 6.0f);
|
|
|
|
UE_LOG(LogTestPAL, Display, TEXT("Running proc test as child (pid %d), will be doing work for %f seconds."), FPlatformProcess::GetCurrentProcessId(), RandomWorkTime);
|
|
|
|
double StartTime = FPlatformTime::Seconds();
|
|
|
|
// Use all the CPU!
|
|
for (;;)
|
|
{
|
|
double CurrentTime = FPlatformTime::Seconds();
|
|
if (CurrentTime - StartTime >= RandomWorkTime)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
UE_LOG(LogTestPAL, Display, TEXT("Child (pid %d) finished work."), FPlatformProcess::GetCurrentProcessId());
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* FProcHandle test (parent instance)
|
|
*/
|
|
int32 ProcRunAsParent(const TCHAR* CommandLine)
|
|
{
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(CommandLine);
|
|
UE_LOG(LogTestPAL, Display, TEXT("Running proc test as parent."));
|
|
|
|
// Run slave instance continuously
|
|
int NumChildrenToSpawn = 255, MaxAtOnce = 5;
|
|
FParent Parent(NumChildrenToSpawn, MaxAtOnce);
|
|
|
|
Parent.Run();
|
|
|
|
UE_LOG(LogTestPAL, Display, TEXT("Parent quit."));
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Tests a single file.
|
|
*/
|
|
void TestCaseInsensitiveFile(const FString & Filename, const FString & WrongFilename)
|
|
{
|
|
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
|
|
|
|
IFileHandle * CreationHandle = PlatformFile.OpenWrite(*Filename);
|
|
checkf(CreationHandle, TEXT("Could not create a test file for '%s'"), *Filename);
|
|
delete CreationHandle;
|
|
|
|
IFileHandle* CheckGoodHandle = PlatformFile.OpenRead(*Filename);
|
|
checkf(CheckGoodHandle, TEXT("Could not open a test file for '%s' (zero probe)"), *Filename);
|
|
delete CheckGoodHandle;
|
|
|
|
IFileHandle* CheckWrongCaseRelHandle = PlatformFile.OpenRead(*WrongFilename);
|
|
checkf(CheckWrongCaseRelHandle, TEXT("Could not open a test file for '%s'"), *WrongFilename);
|
|
delete CheckWrongCaseRelHandle;
|
|
|
|
PlatformFile.DeleteFile(*Filename);
|
|
}
|
|
|
|
/**
|
|
* Case-(in)sensitivity test/
|
|
*/
|
|
int32 CaseTest(const TCHAR* CommandLine)
|
|
{
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(CommandLine);
|
|
UE_LOG(LogTestPAL, Display, TEXT("Running case sensitivity test."));
|
|
|
|
TestCaseInsensitiveFile(TEXT("Test.Test"), TEXT("teSt.teSt"));
|
|
|
|
FString File(TEXT("Test^%!CaseInsens"));
|
|
FString AbsFile = FPaths::ConvertRelativePathToFull(File);
|
|
FString AbsFileUpper = AbsFile.ToUpper();
|
|
|
|
TestCaseInsensitiveFile(AbsFile, AbsFileUpper);
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Message box test/
|
|
*/
|
|
int32 MessageBoxTest(const TCHAR* CommandLine)
|
|
{
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(CommandLine);
|
|
UE_LOG(LogTestPAL, Display, TEXT("Running message box test."));
|
|
|
|
FString Display(TEXT("I am a big big string in a big big game, it's not a big big thing if you print me. But I do do feel that I do do will be displayed wrong, displayed wrong... or not."));
|
|
FString Caption(TEXT("I am a big big caption in a big big game, it's not a big big thing if you print me. But I do do feel that I do do will be displayed wrong, displayed wrong... or not."));
|
|
EAppReturnType::Type Result = FPlatformMisc::MessageBoxExt(EAppMsgType::YesNo, *Display, *Caption);
|
|
|
|
UE_LOG(LogTestPAL, Display, TEXT("MessageBoxExt result: %d."), static_cast<int32>(Result));
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* ************ Thread singleton test *****************
|
|
*/
|
|
|
|
/**
|
|
* Per-thread singleton
|
|
*/
|
|
struct FPerThreadTestSingleton : public TThreadSingleton<FPerThreadTestSingleton>
|
|
{
|
|
FPerThreadTestSingleton()
|
|
{
|
|
UE_LOG(LogTestPAL, Log, TEXT("FPerThreadTestSingleton (this=%p) created for thread %d"),
|
|
this,
|
|
FPlatformTLS::GetCurrentThreadId());
|
|
}
|
|
|
|
void DoSomething()
|
|
{
|
|
UE_LOG(LogTestPAL, Log, TEXT("Thread %d is about to quit"), FPlatformTLS::GetCurrentThreadId());
|
|
}
|
|
|
|
virtual ~FPerThreadTestSingleton()
|
|
{
|
|
UE_LOG(LogTestPAL, Log, TEXT("FPerThreadTestSingleton (%p) destroyed for thread %d"),
|
|
this,
|
|
FPlatformTLS::GetCurrentThreadId());
|
|
}
|
|
};
|
|
|
|
//DECLARE_THREAD_SINGLETON( FPerThreadTestSingleton );
|
|
|
|
/**
|
|
* Thread runnable
|
|
*/
|
|
struct FSingletonTestingThread : public FRunnable
|
|
{
|
|
virtual uint32 Run()
|
|
{
|
|
FPerThreadTestSingleton& Dummy = FPerThreadTestSingleton::Get();
|
|
|
|
FPlatformProcess::Sleep(3.0f);
|
|
|
|
Dummy.DoSomething();
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Thread singleton test
|
|
*/
|
|
int32 ThreadSingletonTest(const TCHAR* CommandLine)
|
|
{
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(CommandLine);
|
|
UE_LOG(LogTestPAL, Display, TEXT("Running thread singleton test."));
|
|
|
|
const int kNumTestThreads = 10;
|
|
|
|
FSingletonTestingThread * RunnableArray[kNumTestThreads] = { nullptr };
|
|
FRunnableThread * ThreadArray[kNumTestThreads] = { nullptr };
|
|
|
|
// start all threads
|
|
for (int Idx = 0; Idx < kNumTestThreads; ++Idx)
|
|
{
|
|
RunnableArray[Idx] = new FSingletonTestingThread();
|
|
ThreadArray[Idx] = FRunnableThread::Create(RunnableArray[Idx],
|
|
*FString::Printf(TEXT("TestThread%d"), Idx));
|
|
}
|
|
|
|
GLog->FlushThreadedLogs();
|
|
GLog->Flush();
|
|
|
|
// join all threads
|
|
for (int Idx = 0; Idx < kNumTestThreads; ++Idx)
|
|
{
|
|
ThreadArray[Idx]->WaitForCompletion();
|
|
delete ThreadArray[Idx];
|
|
ThreadArray[Idx] = nullptr;
|
|
delete RunnableArray[Idx];
|
|
RunnableArray[Idx] = nullptr;
|
|
}
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Sysinfo test
|
|
*/
|
|
int32 SysInfoTest(const TCHAR* CommandLine)
|
|
{
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(CommandLine);
|
|
UE_LOG(LogTestPAL, Display, TEXT("Running system info test."));
|
|
|
|
bool bIsRunningOnBattery = FPlatformMisc::IsRunningOnBattery();
|
|
UE_LOG(LogTestPAL, Display, TEXT(" FPlatformMisc::IsRunningOnBattery() = %s"), bIsRunningOnBattery ? TEXT("true") : TEXT("false"));
|
|
|
|
GenericApplication * PlatformApplication = FPlatformMisc::CreateApplication();
|
|
checkf(PlatformApplication, TEXT("Could not create platform application!"));
|
|
bool bIsMouseAttached = PlatformApplication->IsMouseAttached();
|
|
UE_LOG(LogTestPAL, Display, TEXT(" FPlatformMisc::IsMouseAttached() = %s"), bIsMouseAttached ? TEXT("true") : TEXT("false"));
|
|
|
|
FString OSInstanceGuid = FPlatformMisc::GetOperatingSystemId();
|
|
UE_LOG(LogTestPAL, Display, TEXT(" FPlatformMisc::GetOperatingSystemId() = '%s'"), *OSInstanceGuid);
|
|
|
|
FString UserDir = FPlatformProcess::UserDir();
|
|
UE_LOG(LogTestPAL, Display, TEXT(" FPlatformMisc::UserDir() = '%s'"), *UserDir);
|
|
|
|
FString ApplicationSettingsDir = FPlatformProcess::ApplicationSettingsDir();
|
|
UE_LOG(LogTestPAL, Display, TEXT(" FPlatformMisc::ApplicationSettingsDir() = '%s'"), *ApplicationSettingsDir);
|
|
|
|
FPlatformMemory::DumpStats(*GLog);
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Crash test
|
|
*/
|
|
int32 CrashTest(const TCHAR* CommandLine)
|
|
{
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(CommandLine);
|
|
UE_LOG(LogTestPAL, Display, TEXT("Running crash test (this should not exit)."));
|
|
|
|
// try ensures first (each ensure fires just once)
|
|
{
|
|
for (int IdxEnsure = 0; IdxEnsure < 5; ++IdxEnsure)
|
|
{
|
|
FScopeLogTime EnsureLogTime(*FString::Printf(TEXT("Handled FIRST ensure() #%d times"), IdxEnsure), nullptr, FScopeLogTime::ScopeLog_Seconds);
|
|
ensure(false);
|
|
}
|
|
}
|
|
{
|
|
for (int IdxEnsure = 0; IdxEnsure < 5; ++IdxEnsure)
|
|
{
|
|
FScopeLogTime EnsureLogTime(*FString::Printf(TEXT("Handled SECOND ensure() #%d times"), IdxEnsure), nullptr, FScopeLogTime::ScopeLog_Seconds);
|
|
ensure(false);
|
|
}
|
|
}
|
|
|
|
if (FParse::Param(CommandLine, TEXT("logfatal")))
|
|
{
|
|
UE_LOG(LogTestPAL, Fatal, TEXT(" LogFatal!"));
|
|
}
|
|
else if (FParse::Param(CommandLine, TEXT("check")))
|
|
{
|
|
checkf(false, TEXT(" checkf!"));
|
|
}
|
|
else
|
|
{
|
|
*(int *)0x10 = 0x11;
|
|
}
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* String Precision test
|
|
*/
|
|
int32 StringPrecisionTest(const TCHAR* CommandLine)
|
|
{
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(CommandLine);
|
|
UE_LOG(LogTestPAL, Display, TEXT("Running string precision test."));
|
|
|
|
const FString TestString(TEXT("TestString"));
|
|
int32 Indent = 15;
|
|
UE_LOG(LogTestPAL, Display, TEXT("%*s"), Indent, *TestString);
|
|
UE_LOG(LogTestPAL, Display, TEXT("Begining of the line %*s"), Indent, *TestString);
|
|
UE_LOG(LogTestPAL, Display, TEXT("%*s end of the line"), Indent, *TestString);
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Test Push/PopDll
|
|
*/
|
|
int32 DynamicLibraryTest(const TCHAR* CommandLine)
|
|
{
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(CommandLine);
|
|
UE_LOG(LogTestPAL, Display, TEXT("Attempting to load Steam library"));
|
|
|
|
FString RootSteamPath;
|
|
FString LibraryName;
|
|
|
|
if (PLATFORM_LINUX)
|
|
{
|
|
RootSteamPath = FPaths::EngineDir() / FString(TEXT("Binaries/ThirdParty/Steamworks/Steamv139/x86_64-unknown-linux-gnu/"));
|
|
LibraryName = TEXT("libsteam_api.so");
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogTestPAL, Fatal, TEXT("This test is not implemented for this platform."))
|
|
}
|
|
|
|
FPlatformProcess::PushDllDirectory(*RootSteamPath);
|
|
void* SteamDLLHandle = FPlatformProcess::GetDllHandle(*LibraryName);
|
|
FPlatformProcess::PopDllDirectory(*RootSteamPath);
|
|
|
|
if (SteamDLLHandle == nullptr)
|
|
{
|
|
// try bundled one
|
|
UE_LOG(LogTestPAL, Error, TEXT("Could not load via Push/PopDll, loading directly."));
|
|
SteamDLLHandle = FPlatformProcess::GetDllHandle(*(RootSteamPath + LibraryName));
|
|
|
|
if (SteamDLLHandle == nullptr)
|
|
{
|
|
UE_LOG(LogTestPAL, Fatal, TEXT("Could not load Steam library!"))
|
|
}
|
|
}
|
|
|
|
if (SteamDLLHandle)
|
|
{
|
|
UE_LOG(LogTestPAL, Log, TEXT("Loaded Steam library at %p"), SteamDLLHandle);
|
|
FPlatformProcess::FreeDllHandle(SteamDLLHandle);
|
|
SteamDLLHandle = nullptr;
|
|
}
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* FMalloc::GetAllocationSize() test
|
|
*/
|
|
int32 GetAllocationSizeTest(const TCHAR* CommandLine)
|
|
{
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(CommandLine);
|
|
UE_LOG(LogTestPAL, Display, TEXT("Running GMalloc->GetAllocationSize() test."));
|
|
|
|
struct Allocation
|
|
{
|
|
void * Memory;
|
|
SIZE_T RequestedSize;
|
|
SIZE_T Alignment;
|
|
SIZE_T ActualSize;
|
|
};
|
|
|
|
TArray<Allocation> Allocs;
|
|
SIZE_T TotalMemoryRequested = 0, TotalMemoryAllocated = 0;
|
|
|
|
// force proxy malloc
|
|
FMalloc* OldGMalloc = GMalloc;
|
|
GMalloc = new FMallocPoisonProxy(GMalloc);
|
|
|
|
// allocate all the memory and initialize with 0
|
|
for (uint32 Size = 16; Size < 4096; Size += 16)
|
|
{
|
|
for (SIZE_T AlignmentPower = 4; AlignmentPower <= 7; ++AlignmentPower)
|
|
{
|
|
SIZE_T Alignment = ((SIZE_T)1 << AlignmentPower);
|
|
|
|
Allocation New;
|
|
New.RequestedSize = Size;
|
|
New.Alignment = Alignment;
|
|
New.Memory = GMalloc->Malloc(New.RequestedSize, New.Alignment);
|
|
if (!GMalloc->GetAllocationSize(New.Memory, New.ActualSize))
|
|
{
|
|
UE_LOG(LogTestPAL, Fatal, TEXT("Could not get allocation size for %p"), New.Memory);
|
|
}
|
|
FMemory::Memzero(New.Memory, New.RequestedSize);
|
|
|
|
TotalMemoryRequested += New.RequestedSize;
|
|
TotalMemoryAllocated += New.ActualSize;
|
|
|
|
Allocs.Add(New);
|
|
}
|
|
}
|
|
|
|
UE_LOG(LogTestPAL, Log, TEXT("Allocated %llu memory (%llu requested) in %d chunks"), TotalMemoryAllocated, TotalMemoryRequested, Allocs.Num());
|
|
|
|
if (FParse::Param(CommandLine, TEXT("realloc")))
|
|
{
|
|
for (Allocation & Alloc : Allocs)
|
|
{
|
|
// resize
|
|
Alloc.RequestedSize += 16;
|
|
Alloc.Memory = GMalloc->Realloc(Alloc.Memory, Alloc.RequestedSize, Alloc.Alignment);
|
|
FMemory::Memzero(Alloc.Memory, Alloc.RequestedSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (Allocation & Alloc : Allocs)
|
|
{
|
|
// only fill the difference, if any
|
|
if (Alloc.ActualSize > Alloc.RequestedSize)
|
|
{
|
|
SIZE_T Difference = Alloc.ActualSize - Alloc.RequestedSize;
|
|
FMemory::Memset((void *)((SIZE_T)Alloc.Memory + Alloc.RequestedSize), 0xAA, Difference);
|
|
}
|
|
}
|
|
}
|
|
|
|
// check if any alloc got stomped
|
|
for (Allocation & Alloc : Allocs)
|
|
{
|
|
for (SIZE_T Idx = 0; Idx < Alloc.RequestedSize; ++Idx)
|
|
{
|
|
if (((const uint8 *)Alloc.Memory)[Idx] != 0)
|
|
{
|
|
UE_LOG(LogTestPAL, Fatal, TEXT("Allocation at %p (offset %llu) got stomped with 0x%x"),
|
|
Alloc.Memory, Idx, ((const uint8 *)Alloc.Memory)[Idx]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
UE_LOG(LogTestPAL, Log, TEXT("No memory stomping detected"));
|
|
|
|
for (Allocation & Alloc : Allocs)
|
|
{
|
|
GMalloc->Free(Alloc.Memory);
|
|
}
|
|
GMalloc = OldGMalloc;
|
|
|
|
Allocs.Empty();
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Selects and runs one of test cases.
|
|
*
|
|
* @param ArgC Number of commandline arguments.
|
|
* @param ArgV Commandline arguments.
|
|
* @return Test case's return code.
|
|
*/
|
|
int32 MultiplexedMain(int32 ArgC, char* ArgV[])
|
|
{
|
|
for (int32 IdxArg = 0; IdxArg < ArgC; ++IdxArg)
|
|
{
|
|
if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_PROC_TEST_CHILD))
|
|
{
|
|
return ProcRunAsChild(*TestPAL::CommandLine);
|
|
}
|
|
else if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_PROC_TEST))
|
|
{
|
|
return ProcRunAsParent(*TestPAL::CommandLine);
|
|
}
|
|
else if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_CASE_SENSITIVITY_TEST))
|
|
{
|
|
return CaseTest(*TestPAL::CommandLine);
|
|
}
|
|
else if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_MESSAGEBOX_TEST))
|
|
{
|
|
return MessageBoxTest(*TestPAL::CommandLine);
|
|
}
|
|
else if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_DIRECTORY_WATCHER_TEST))
|
|
{
|
|
return DirectoryWatcherTest(*TestPAL::CommandLine);
|
|
}
|
|
else if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_THREAD_SINGLETON_TEST))
|
|
{
|
|
return ThreadSingletonTest(*TestPAL::CommandLine);
|
|
}
|
|
else if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_SYSINFO_TEST))
|
|
{
|
|
return SysInfoTest(*TestPAL::CommandLine);
|
|
}
|
|
else if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_CRASH_TEST))
|
|
{
|
|
return CrashTest(*TestPAL::CommandLine);
|
|
}
|
|
else if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_STRINGPRECISION_TEST))
|
|
{
|
|
return StringPrecisionTest(*TestPAL::CommandLine);
|
|
}
|
|
else if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_DSO_TEST))
|
|
{
|
|
return DynamicLibraryTest(*TestPAL::CommandLine);
|
|
}
|
|
else if (!FCStringAnsi::Strcmp(ArgV[IdxArg], ARG_GET_ALLOCATION_SIZE_TEST))
|
|
{
|
|
return GetAllocationSizeTest(*TestPAL::CommandLine);
|
|
}
|
|
}
|
|
|
|
FPlatformMisc::SetCrashHandler(NULL);
|
|
FPlatformMisc::SetGracefulTerminationHandler();
|
|
|
|
GEngineLoop.PreInit(*TestPAL::CommandLine);
|
|
UE_LOG(LogTestPAL, Warning, TEXT("Unable to find any known test name, no test started."));
|
|
|
|
UE_LOG(LogTestPAL, Warning, TEXT(""));
|
|
UE_LOG(LogTestPAL, Warning, TEXT("Available test cases:"));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(" %s: test process handling API"), ANSI_TO_TCHAR( ARG_PROC_TEST ));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(" %s: test case-insensitive file operations"), ANSI_TO_TCHAR( ARG_CASE_SENSITIVITY_TEST ));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(" %s: test message box bug (too long strings)"), ANSI_TO_TCHAR( ARG_MESSAGEBOX_TEST ));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(" %s: test directory watcher"), ANSI_TO_TCHAR( ARG_DIRECTORY_WATCHER_TEST ));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(" %s: test per-thread singletons"), ANSI_TO_TCHAR( ARG_THREAD_SINGLETON_TEST ));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(" %s: test (some) system information"), ANSI_TO_TCHAR( ARG_SYSINFO_TEST ));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(" %s: test crash handling (pass '-logfatal' for testing Fatal logs)"), ANSI_TO_TCHAR( ARG_CRASH_TEST ));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(" %s: test passing %%*s in a format string"), ANSI_TO_TCHAR( ARG_STRINGPRECISION_TEST ));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(" %s: test APIs for dealing with dynamic libraries"), ANSI_TO_TCHAR( ARG_DSO_TEST ));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(" %s: test GMalloc->GetAllocationSize()"), UTF8_TO_TCHAR(ARG_GET_ALLOCATION_SIZE_TEST));
|
|
UE_LOG(LogTestPAL, Warning, TEXT(""));
|
|
UE_LOG(LogTestPAL, Warning, TEXT("Pass one of those to run an appropriate test."));
|
|
|
|
FEngineLoop::AppPreExit();
|
|
FEngineLoop::AppExit();
|
|
return 1;
|
|
}
|
|
|
|
int32 main(int32 ArgC, char* ArgV[])
|
|
{
|
|
TestPAL::CommandLine = TEXT("");
|
|
|
|
for (int32 Option = 1; Option < ArgC; Option++)
|
|
{
|
|
TestPAL::CommandLine += TEXT(" ");
|
|
FString Argument(ANSI_TO_TCHAR(ArgV[Option]));
|
|
if (Argument.Contains(TEXT(" ")))
|
|
{
|
|
if (Argument.Contains(TEXT("=")))
|
|
{
|
|
FString ArgName;
|
|
FString ArgValue;
|
|
Argument.Split( TEXT("="), &ArgName, &ArgValue );
|
|
Argument = FString::Printf( TEXT("%s=\"%s\""), *ArgName, *ArgValue );
|
|
}
|
|
else
|
|
{
|
|
Argument = FString::Printf(TEXT("\"%s\""), *Argument);
|
|
}
|
|
}
|
|
TestPAL::CommandLine += Argument;
|
|
}
|
|
|
|
return MultiplexedMain(ArgC, ArgV);
|
|
}
|