UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
Utils.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "AutoRTFMDefines.h"
6#if (defined(__AUTORTFM) && __AUTORTFM)
7
8#include "AutoRTFM.h"
9#include "BuildMacros.h"
10#include "ExternAPI.h"
11
12#include <cstdarg>
13#include <string>
14#include <type_traits>
15
16// If 0 then verbose logging is compiled-out.
17#define AUTORTFM_VERBOSE_ENABLED 0
18
19// AutoRTFM internal-runtime-only attribute that can be applied to classes,
20// methods or functions to prevent AutoRTFM closed function(s) from being
21// generated. Applying the annotation to a class is equivalent to applying the
22// annotation to each method of the class.
23// When annotating a function, the attribute must be placed on a the function
24// declaration (usually in the header) and not a function implementation.
25// Annotated functions are callable from both the open and closed, without
26// trampolines or validation, and the function is always uninstrumented.
27// Note: This annotation will prevent inlining of annotated functions.
28#define AUTORTFM_INTERNAL [[clang::autortfm(internal)]]
29
30namespace AutoRTFM
31{
32
33// Reports an internal AutoRTFM issue. The behavior of this function will vary
34// based on ForTheRuntime::GetInternalAbortAction() and
35// ForTheRuntime::GetEnsureOnInternalAbort().
36// If ProgramCounter is null, then the return address of the call will be used.
38UE_AUTORTFM_API void ReportError(const char* File, int Line, void* ProgramCounter, const char* Format, ...);
39
40[[noreturn]] inline void InternalUnreachable(); //-V1082 Silence PVS [[noreturn]] false positive warning
41
42std::string GetFunctionDescription(void* FunctionPtr);
43
45std::string GetFunctionDescription(TReturnType (*FunctionPtr)(TParameterTypes...))
46{
47 return GetFunctionDescription(reinterpret_cast<void*>(FunctionPtr));
48}
49
50// We use a special calling convention for this call to minimize
51// the cost of calling this function (which is super unlikely to
52// be called because it is the asserting true codepath, EG. only
53// fatal process destroying explosions happen here).
54[[clang::preserve_most, noreturn]]
56
57// We use a special calling convention for this call to minimize
58// the cost of calling this function (which is super unlikely to
59// be called because it is the expecting true codepath, EG. only
60// things we don't expect to happen get here).
61[[clang::preserve_most]]
63
64// Logs a message using a printf-style format string and va_list arguments.
65inline void LogV(const char* File, int Line, void* ProgramCounter, autortfm_log_severity Severity, const char* Format, va_list Args)
66{
67 if (ProgramCounter == nullptr)
68 {
69 ProgramCounter = __builtin_return_address(0);
70 }
71
72 GExternAPI.Log(File, Line, ProgramCounter, Severity, Format, Args);
73}
74
75// Logs a message using a printf-style format string and variadic arguments.
77inline void Log(const char* File, int Line, void* ProgramCounter, autortfm_log_severity Severity, const char* Format, ...)
78{
79 if (ProgramCounter == nullptr)
80 {
81 ProgramCounter = __builtin_return_address(0);
82 }
83
84 va_list Args;
85 va_start(Args, Format);
86 GExternAPI.Log(File, Line, ProgramCounter, Severity, Format, Args);
87 va_end(Args);
88}
89
90// Logs a message with a callstack using a printf-style format string and va_list arguments.
91inline void LogWithCallstackV(autortfm_log_severity Severity, const char* Format, va_list Args)
92{
93 GExternAPI.LogWithCallstack(__builtin_return_address(0), Severity, Format, Args);
94}
95
96// Logs a message with a callstack using a printf-style format string and variadic arguments.
98inline void LogWithCallstack(autortfm_log_severity Severity, const char* Format, ...)
99{
100 va_list Args;
101 va_start(Args, Format);
102 GExternAPI.LogWithCallstack(__builtin_return_address(0), Severity, Format, Args);
103 va_end(Args);
104}
105
106// Reports an ensure failure using a printf-style format string and va_list arguments.
107// If ProgramCounter is null, then the return address of the call will be used.
108inline void EnsureFailureV(const char* File, int Line, void* ProgramCounter, const char* Condition, const char* Format, va_list Args)
109{
110 if (ProgramCounter == nullptr)
111 {
112 ProgramCounter = __builtin_return_address(0);
113 }
114
115 GExternAPI.EnsureFailure(File, Line, ProgramCounter, Condition, Format, Args);
116}
117
118// Reports an ensure failure using a printf-style format string and variadic arguments.
119// If ProgramCounter is null, then the return address of the call will be used.
121inline void EnsureFailure(const char* File, int Line, void* ProgramCounter, const char* Condition, const char* Format, ...)
122{
123 if (ProgramCounter == nullptr)
124 {
125 ProgramCounter = __builtin_return_address(0);
126 }
127
128 va_list Args;
129 va_start(Args, Format);
130 GExternAPI.EnsureFailure(File, Line, ProgramCounter, Condition, Format, Args);
131 va_end(Args);
132}
133
134// Rounds Value up to the next multiple of Alignment.
135// Alignment must be a power of two.
136template<typename T>
137inline constexpr T AlignDown(T Value, T Alignment)
138{
139 static_assert(std::is_integral_v<T>);
140 return Value & ~(Alignment - 1);
141}
142
143// Rounds Value down to the next multiple of Alignment.
144// Alignment must be a power of two.
145template<typename T>
146inline constexpr T AlignUp(T Value, T Alignment)
147{
148 static_assert(std::is_integral_v<T>);
149 return (Value + Alignment - 1) & ~(Alignment - 1);
150}
151
152// Rounds Value up to the next multiple of Multiple.
153// Unlike AlignDown(), Multiple does not need to be a power of two.
154template<typename T>
155inline constexpr T RoundDown(T Value, T Multiple)
156{
157 static_assert(std::is_integral_v<T>);
158 return (Value / Multiple) * Multiple;
159}
160
161// Rounds Value down to the next multiple of Multiple.
162// Unlike AlignUp(), Multiple does not need to be a power of two.
163template<typename T>
164inline constexpr T RoundUp(T Value, T Multiple)
165{
166 static_assert(std::is_integral_v<T>);
167 return RoundDown(Value + Multiple - 1, Multiple);
168}
169
170// Returns the linear interpolation between Start and End using the coefficient Fraction.
171template<typename T>
172inline constexpr T Lerp(T Start, T End, T Fraction)
173{
174 return Start + Fraction * (End - Start);
175}
176
177} // namespace AutoRTFM
178
179#define AUTORTFM_LIKELY(x) __builtin_expect(!!(x), 1)
180#define AUTORTFM_UNLIKELY(x) __builtin_expect(!!(x), 0)
181
182#define AUTORTFM_REQUIRE_SEMICOLON static_assert(true)
183
184#define AUTORTFM_REPORT_ERROR(Format, ...) ::AutoRTFM::ReportError(__FILE__, __LINE__, /* ProgramCounter */ nullptr, Format, ##__VA_ARGS__)
185
186#define AUTORTFM_VERBOSE(Format, ...) ::AutoRTFM::Log(__FILE__, __LINE__, /* ProgramCounter */ nullptr, autortfm_log_verbose, Format, ##__VA_ARGS__)
187#define AUTORTFM_LOG(Format, ...) ::AutoRTFM::Log(__FILE__, __LINE__, /* ProgramCounter */ nullptr, autortfm_log_info, Format, ##__VA_ARGS__)
188#define AUTORTFM_WARN(Format, ...) ::AutoRTFM::Log(__FILE__, __LINE__, /* ProgramCounter */ nullptr, autortfm_log_warn, Format, ##__VA_ARGS__)
189#define AUTORTFM_ERROR(Format, ...) ::AutoRTFM::Log(__FILE__, __LINE__, /* ProgramCounter */ nullptr, autortfm_log_error, Format, ##__VA_ARGS__)
190#define AUTORTFM_FATAL(Format, ...) ::AutoRTFM::Log(__FILE__, __LINE__, /* ProgramCounter */ nullptr, autortfm_log_fatal, Format, ##__VA_ARGS__)
191
192#define AUTORTFM_VERBOSE_V(Format, Args) ::AutoRTFM::LogV(__FILE__, __LINE__, /* ProgramCounter */ nullptr, autortfm_log_verbose, Format, Args)
193#define AUTORTFM_LOG_V(Format, Args) ::AutoRTFM::LogV(__FILE__, __LINE__, /* ProgramCounter */ nullptr, autortfm_log_info, Format, Args)
194#define AUTORTFM_WARN_V(Format, Args) ::AutoRTFM::LogV(__FILE__, __LINE__, /* ProgramCounter */ nullptr, autortfm_log_warn, Format, Args)
195#define AUTORTFM_ERROR_V(Format, Args) ::AutoRTFM::LogV(__FILE__, __LINE__, /* ProgramCounter */ nullptr, autortfm_log_error, Format, Args)
196#define AUTORTFM_FATAL_V(Format, Args) ::AutoRTFM::LogV(__FILE__, __LINE__, /* ProgramCounter */ nullptr, autortfm_log_fatal, Format, Args)
197
198#define AUTORTFM_VERBOSE_IF(Condition, Format, ...) do { if (Condition) { AUTORTFM_VERBOSE(Format, ##__VA_ARGS__); } } while(false)
199#define AUTORTFM_LOG_IF(Condition, Format, ...) do { if (Condition) { AUTORTFM_LOG(Format, ##__VA_ARGS__); } } while(false)
200#define AUTORTFM_WARN_IF(Condition, Format, ...) do { if (Condition) { AUTORTFM_WARN(Format, ##__VA_ARGS__); } } while(false)
201#define AUTORTFM_ERROR_IF(Condition, Format, ...) do { if (AUTORTFM_UNLIKELY(Condition)) { AUTORTFM_ERROR(Format, ##__VA_ARGS__); } } while(false)
202#define AUTORTFM_FATAL_IF(Condition, Format, ...) do { if (AUTORTFM_UNLIKELY(Condition)) { AUTORTFM_FATAL(Format, ##__VA_ARGS__); } } while(false)
203
204// If AUTORTFM_VERBOSE_ENABLED is 0, then replace all the verbose logging macros
205// with no-ops.
206#if !AUTORTFM_VERBOSE_ENABLED
207#undef AUTORTFM_VERBOSE
208#undef AUTORTFM_VERBOSE_V
209#undef AUTORTFM_VERBOSE_IF
210#define AUTORTFM_VERBOSE(...) AUTORTFM_REQUIRE_SEMICOLON
211#define AUTORTFM_VERBOSE_V(...) AUTORTFM_REQUIRE_SEMICOLON
212#define AUTORTFM_VERBOSE_IF(...) AUTORTFM_REQUIRE_SEMICOLON
213#endif
214
215#define AUTORTFM_ENSURE(Condition) do { \
216 if (AUTORTFM_UNLIKELY(!(Condition))) { \
217 [[maybe_unused]] static bool bCalled = [] { \
218 ::AutoRTFM::EnsureFailure(__FILE__, __LINE__, /* ProgramCounter */ nullptr, #Condition, nullptr); \
219 return true; \
220 }(); \
221 } } while(false)
222
223#define AUTORTFM_ENSURE_MSG(Condition, Format, ...) do { \
224 if (AUTORTFM_UNLIKELY(!(Condition))) { \
225 [[maybe_unused]] static bool bCalled = [&] { \
226 ::AutoRTFM::EnsureFailure(__FILE__, __LINE__, /* ProgramCounter */ nullptr, #Condition, Format, ##__VA_ARGS__); \
227 return true; \
228 }(); \
229 } } while(false)
230
231#define AUTORTFM_ENSURE_MSG_V(Condition, Format, Args) do { \
232 if (AUTORTFM_UNLIKELY(!(Condition))) { \
233 [[maybe_unused]] static bool bCalled = [&] { \
234 ::AutoRTFM::EnsureFailureV(__FILE__, __LINE__, /* ProgramCounter */ nullptr, #Condition, Format, Args); \
235 return true; \
236 }(); \
237 } } while(false)
238
239#define AUTORTFM_DUMP_STACKTRACE(Message, ...) ::AutoRTFM::LogWithCallstack(autortfm_log_error, Message, ##__VA_ARGS__)
240
241// This is all a bit funky - but for good reason! We want `AUTORTFM_ASSERT`
242// to be as close to *zero* cost if the assert wouldn't trigger.
243// We will always pay the cost of the unlikely branch, but we need
244// to make the body of taking the assert happen in another function
245// so as not to affect codegen, register allocation, and stack
246// reservation. But we also want the `AUTORTFM_ASSERT` to give us accurate
247// `__FILE__` and `__LINE__` information for the line that it was
248// triggered on. So what we do is have a lambda at the line that
249// actually does the assert (but crucially gets the correct file
250// and line numbers), but then pass this to another function
251// `DoAssert` which has a special calling convention that makes
252// the caller as optimal as possible (at the expense of the callee).
253#define AUTORTFM_ASSERT(exp) \
254 if (AUTORTFM_UNLIKELY(!(exp))) \
255 { \
256 auto Lambda = [] \
257 { \
258 AUTORTFM_FATAL("AUTORTFM_ASSERT(%s) failure", #exp); \
259 }; \
260 AutoRTFM::DoAssert(Lambda); \
261 }
262
263// For places where zero cost is truly important, AUTORTFM_ASSERT_DEBUG will
264// disappear entirely in Shipping and Test builds. We still evaluate the expression,
265// on the off-chance that we are given an expression with side effects, and rely on
266// the compiler to optimize away a dead expression.
267#if AUTORTFM_BUILD_SHIPPING || AUTORTFM_BUILD_TEST
268#define AUTORTFM_ASSERT_DEBUG(exp) ((void)AUTORTFM_LIKELY(static_cast<bool>(exp)))
269#else
270#define AUTORTFM_ASSERT_DEBUG(exp) \
271 if (AUTORTFM_UNLIKELY(!(exp))) \
272 { \
273 auto Lambda = [] \
274 { \
275 AUTORTFM_FATAL("AUTORTFM_ASSERT_DEBUG(%s) failure", #exp); \
276 }; \
277 AutoRTFM::DoAssert(Lambda); \
278 }
279#endif
280
281// Same funkiness as AUTORTFM_ASSERT, except that it doesn't cause a fatal error.
282// TODO: Maybe upgrade the Info -> Warning?
283#define AUTORTFM_EXPECT(exp) \
284 if (AUTORTFM_UNLIKELY(!(exp))) \
285 { \
286 auto Lambda = [] \
287 { \
288 ::AutoRTFM::LogWithCallstack(autortfm_log_info, "AUTORTFM_EXPECT(%s) failure", #exp); \
289 }; \
290 AutoRTFM::DoExpect(Lambda); \
291 }
292
293#if defined(__has_feature)
294#if __has_feature(address_sanitizer)
295#define AUTORTFM_NO_ASAN [[clang::no_sanitize("address")]]
296#endif
297#endif
298
299#if !defined(AUTORTFM_NO_ASAN)
300#define AUTORTFM_NO_ASAN
301#endif
302
303#if defined(__clang__)
304#define AUTORTFM_MUST_TAIL [[clang::musttail]]
305#endif
306
307#if !defined(AUTORTFM_MUST_TAIL)
308#define AUTORTFM_MUST_TAIL
309#endif
310
311#if !defined(CA_SUPPRESS)
312#define CA_SUPPRESS( WarningNumber )
313#endif
314
315[[noreturn]] inline void AutoRTFM::InternalUnreachable() //-V1082 Silence PVS [[noreturn]] false positive warning
316{
317 AUTORTFM_FATAL("Unreachable encountered!");
319}
320
321#endif // (defined(__AUTORTFM) && __AUTORTFM)
constexpr T AlignDown(T Val, uint64 Alignment)
Definition AlignmentTemplates.h:34
#define UE_AUTORTFM_FORCENOINLINE
Definition AutoRTFMDefines.h:173
#define AUTORTFM_DISABLE
Definition AutoRTFMDefines.h:116
#define UE_AUTORTFM_API
Definition AutoRTFMDefines.h:156
autortfm_log_severity
Definition AutoRTFM.h:77
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
float swift_float2 __attribute__((__ext_vector_type__(2)))
Definition MarketplaceKitWrapper.h:67
Definition API.cpp:57
@ Start
Definition GeoEnum.h:100
@ Multiple
[PropertyMetadata] Used for numeric properties. Stipulates that the value must be a multiple of the m...
Definition ObjectMacros.h:1446
ULANG_FORCEINLINE constexpr T AlignUp(T Val, uint64_t Alignment)
Definition Storage.h:93