| 316 | } |
| 317 | |
| 318 | void PlatformBase::Fatal(const StringView& msg, void* context, FatalErrorType error) |
| 319 | { |
| 320 | // Let only one thread to report the error (and wait for it to end to have valid log before crash) |
| 321 | RETRY: |
| 322 | if (Platform::InterlockedCompareExchange(&FatalReporting, 1, 0) != 0) |
| 323 | { |
| 324 | Platform::Sleep(1); |
| 325 | goto RETRY; |
| 326 | } |
| 327 | |
| 328 | // Check if is already during fatal state |
| 329 | if (Engine::FatalError != FatalErrorType::None) |
| 330 | { |
| 331 | // Just send one more error to the log and back |
| 332 | LOG(Error, "Error after fatal error: {0}", msg); |
| 333 | Platform::AtomicStore(&FatalReporting, 0); |
| 334 | return; |
| 335 | } |
| 336 | |
| 337 | // Free OOM safety buffer |
| 338 | Allocator::Free(OutOfMemoryBuffer); |
| 339 | OutOfMemoryBuffer = nullptr; |
| 340 | |
| 341 | // Set flags |
| 342 | PRAGMA_DISABLE_DEPRECATION_WARNINGS; |
| 343 | Globals::FatalErrorOccurred = true; |
| 344 | Globals::IsRequestingExit = true; |
| 345 | Globals::ExitCode = -Math::Max((int32)error, 1); |
| 346 | PRAGMA_ENABLE_DEPRECATION_WARNINGS; |
| 347 | Engine::IsRequestingExit = true; |
| 348 | Engine::ExitCode = -Math::Max((int32)error, 1); |
| 349 | Engine::FatalError = error; |
| 350 | Engine::RequestingExit(); |
| 351 | |
| 352 | // Collect crash info (platform-dependant implementation that might collect stack trace and/or create memory dump) |
| 353 | #if LOG_ENABLE |
| 354 | { |
| 355 | // Log separation for crash info |
| 356 | LOG_FLUSH(); |
| 357 | LOG_FLOOR(); |
| 358 | LOG(Error, ""); |
| 359 | LOG(Error, "Critical error! Reason: {0}", msg); |
| 360 | LOG(Error, ""); |
| 361 | |
| 362 | // Log stack trace |
| 363 | const auto stackFrames = Platform::GetStackFrames(context ? 0 : 1, 60, context); |
| 364 | if (stackFrames.HasItems()) |
| 365 | { |
| 366 | LOG(Error, "Stack trace:"); |
| 367 | for (const auto& frame : stackFrames) |
| 368 | { |
| 369 | // Remove any path from the module name |
| 370 | int32 num = StringUtils::Length(frame.ModuleName); |
| 371 | while (num > 0 && frame.ModuleName[num - 1] != '\\' && frame.ModuleName[num - 1] != '/' && frame.ModuleName[num - 1] != ':') |
| 372 | num--; |
| 373 | StringAsUTF16<ARRAY_COUNT(StackFrame::ModuleName)> moduleName(frame.ModuleName + num); |
| 374 | num = moduleName.Length(); |
| 375 | if (num != 0 && num < ARRAY_COUNT(StackFrame::ModuleName) - 2) |
no test coverage detected