// Copyright Epic Games, Inc. All Rights Reserved. #if (defined(__AUTORTFM) && __AUTORTFM) #include "Utils.h" #include "ContextInlines.h" #include "BuildMacros.h" #include #if AUTORTFM_PLATFORM_WINDOWS #include "WindowsHeader.h" #include #else #include #endif namespace AutoRTFM { std::string GetFunctionDescription(void* FunctionPtr) { #if AUTORTFM_PLATFORM_WINDOWS // This is gross, but it works. It's possible for someone to have SymInitialized before. But if they had, then this // will just fail. Also, this function is called in cases where we're failing, so it's ok if we do dirty things. SymInitialize(GetCurrentProcess(), nullptr, true); DWORD64 Displacement = 0; DWORD64 Address = reinterpret_cast(FunctionPtr); char Buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; PSYMBOL_INFO Symbol = reinterpret_cast(Buffer); Symbol->SizeOfStruct = sizeof(SYMBOL_INFO); Symbol->MaxNameLen = MAX_SYM_NAME; if (SymFromAddr(GetCurrentProcess(), Address, &Displacement, Symbol)) { return Symbol->Name; } else { return ""; } #else // AUTORTFM_PLATFORM_WINDOWS -> so !AUTORTFM_PLATFORM_WINDOWS char** const symbols = backtrace_symbols(&FunctionPtr, 1); std::string Name(*symbols); free(symbols); return Name; #endif // AUTORTFM_PLATFORM_WINDOWS -> so !AUTORTFM_PLATFORM_WINDOWS } UE_AUTORTFM_API UE_AUTORTFM_FORCENOINLINE void ReportError(const char* File, int Line, void* ProgramCounter, const char* Format, ...) { if (ProgramCounter == nullptr) { ProgramCounter = __builtin_return_address(0); } const ForTheRuntime::EAutoRTFMInternalAbortActionState InternalAbortAction = ForTheRuntime::GetInternalAbortAction(); if (Format) { if (InternalAbortAction == ForTheRuntime::EAutoRTFMInternalAbortActionState::Crash) { va_list Args; va_start(Args, Format); ::AutoRTFM::LogV(File, Line, ProgramCounter, autortfm_log_fatal, Format, Args); va_end(Args); } else if (ForTheRuntime::GetEnsureOnInternalAbort()) { va_list Args; va_start(Args, Format); [[maybe_unused]] static bool bCalled = [&] { ::AutoRTFM::EnsureFailureV(File, Line, ProgramCounter, "!GetEnsureOnInternalAbort()", Format, Args); return true; }(); va_end(Args); } } else { if (InternalAbortAction == ForTheRuntime::EAutoRTFMInternalAbortActionState::Crash) { ::AutoRTFM::Log(File, Line, ProgramCounter, autortfm_log_fatal, "Transaction failing because of internal issue"); } else if (ForTheRuntime::GetEnsureOnInternalAbort()) { [[maybe_unused]] static bool bCalled = [&] { ::AutoRTFM::EnsureFailure(File, Line, ProgramCounter, "!GetEnsureOnInternalAbort()", "Transaction failing because of internal issue"); return true; }(); } } if (FContext* const Context = FContext::Get()) { if (InternalAbortAction == ForTheRuntime::EAutoRTFMInternalAbortActionState::Abort) { Context->AbortByLanguageAndThrow(); } else { TTask Task = [] { AUTORTFM_ENSURE(ForTheRuntime::SetAutoRTFMRuntime(ForTheRuntime::AutoRTFM_ForcedDisabled)); }; Context->AbortTransactionWithPostAbortCallback(EContextStatus::AbortedByCascadingRetry, std::move(Task)); } } } } // namespace AutoRTFM #endif // defined(__AUTORTFM) && __AUTORTFM