fprime/Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.cpp
Kyle Jones 513582f420
Add logic for assert failure short circuiting in AssertFatalAdapter (#4042)
* Add logic for assertion short circuiting

- Add guard logic to AssertFatalAdapter to prevent a cascading FW_ASSERT chain from occurring
- If any assert checks fail while handling an in-progress assert check failure, reportAssert will log the
additional assert and execute the system-specific assert handler before returning

* Update assert guard logic to counter based

- Instead of using a bool guard to determine when to off-ramp from a series of FW_ASSERT check failures,
use a counter that is configurable in a program's FpConfig.h file

---------

Co-authored-by: M Starch <LeStarch@googlemail.com>
2025-08-27 09:56:06 -07:00

150 lines
6.5 KiB
C++

// ======================================================================
// \title AssertFatalAdapterImpl.cpp
// \author tcanham
// \brief cpp file for AssertFatalAdapter component implementation class
//
// \copyright
// Copyright 2009-2015, by the California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged.
//
// ======================================================================
#include <Fw/FPrimeBasicTypes.hpp>
#include <Fw/Logger/Logger.hpp>
#include <Fw/Types/Assert.hpp>
#include <Svc/AssertFatalAdapter/AssertFatalAdapterComponentImpl.hpp>
#include <cassert>
#include <cstdio>
namespace Fw {
void defaultReportAssert(FILE_NAME_ARG file,
FwSizeType lineNo,
FwSizeType numArgs,
FwAssertArgType arg1,
FwAssertArgType arg2,
FwAssertArgType arg3,
FwAssertArgType arg4,
FwAssertArgType arg5,
FwAssertArgType arg6,
CHAR* destBuffer,
FwSizeType buffSize);
}
namespace Svc {
// ----------------------------------------------------------------------
// Construction, initialization, and destruction
// ----------------------------------------------------------------------
AssertFatalAdapterComponentImpl ::AssertFatalAdapterComponentImpl(const char* const compName)
: AssertFatalAdapterComponentBase(compName) {
// register component with adapter
this->m_adapter.regAssertReporter(this);
// register adapter
this->m_adapter.registerHook();
// Initialize the assert counter
this->m_assertCount = 0;
}
AssertFatalAdapterComponentImpl ::~AssertFatalAdapterComponentImpl() {}
void AssertFatalAdapterComponentImpl::AssertFatalAdapter::reportAssert(FILE_NAME_ARG file,
FwSizeType lineNo,
FwSizeType numArgs,
FwAssertArgType arg1,
FwAssertArgType arg2,
FwAssertArgType arg3,
FwAssertArgType arg4,
FwAssertArgType arg5,
FwAssertArgType arg6) {
if (m_compPtr) {
m_compPtr->reportAssert(file, lineNo, numArgs, arg1, arg2, arg3, arg4, arg5, arg6);
} else {
// Can't assert, what else can we do? Maybe somebody will see it.
Fw::Logger::log("Svc::AssertFatalAdapter not registered!\n");
assert(0);
}
}
void AssertFatalAdapterComponentImpl::AssertFatalAdapter::regAssertReporter(AssertFatalAdapterComponentImpl* compPtr) {
this->m_compPtr = compPtr;
}
AssertFatalAdapterComponentImpl::AssertFatalAdapter::AssertFatalAdapter() : m_compPtr(nullptr) {}
AssertFatalAdapterComponentImpl::AssertFatalAdapter::~AssertFatalAdapter() {}
void AssertFatalAdapterComponentImpl::AssertFatalAdapter::doAssert() {
// do nothing since there will be a FATAL
}
void AssertFatalAdapterComponentImpl::reportAssert(FILE_NAME_ARG file,
FwSizeType lineNo,
FwSizeType numArgs,
FwAssertArgType arg1,
FwAssertArgType arg2,
FwAssertArgType arg3,
FwAssertArgType arg4,
FwAssertArgType arg5,
FwAssertArgType arg6) {
#if FW_ASSERT_LEVEL == FW_FILEID_ASSERT
Fw::LogStringArg fileArg;
fileArg.format("0x%08" PRIX32, file);
#else
Fw::LogStringArg fileArg(file);
#endif
CHAR msg[Fw::StringBase::BUFFER_SIZE(FW_ASSERT_TEXT_SIZE)] = {0};
Fw::defaultReportAssert(file, static_cast<U32>(lineNo), numArgs, arg1, arg2, arg3, arg4, arg5, arg6, msg,
sizeof(msg));
Fw::Logger::log("%s\n", msg);
// Increment active assert counter
this->m_assertCount++;
// Handle the case where the ports aren't connected yet or we've surpassed the maximum cascading FW_ASSERT failures
if (not this->isConnected_Log_OutputPort(0) || this->m_assertCount > FW_ASSERT_COUNT_MAX) {
assert(0);
return;
}
switch (numArgs) {
case 0:
this->log_FATAL_AF_ASSERT_0(fileArg, static_cast<U32>(lineNo));
break;
case 1:
this->log_FATAL_AF_ASSERT_1(fileArg, static_cast<U32>(lineNo), static_cast<U32>(arg1));
break;
case 2:
this->log_FATAL_AF_ASSERT_2(fileArg, static_cast<U32>(lineNo), static_cast<U32>(arg1),
static_cast<U32>(arg2));
break;
case 3:
this->log_FATAL_AF_ASSERT_3(fileArg, static_cast<U32>(lineNo), static_cast<U32>(arg1),
static_cast<U32>(arg2), static_cast<U32>(arg3));
break;
case 4:
this->log_FATAL_AF_ASSERT_4(fileArg, static_cast<U32>(lineNo), static_cast<U32>(arg1),
static_cast<U32>(arg2), static_cast<U32>(arg3), static_cast<U32>(arg4));
break;
case 5:
this->log_FATAL_AF_ASSERT_5(fileArg, static_cast<U32>(lineNo), static_cast<U32>(arg1),
static_cast<U32>(arg2), static_cast<U32>(arg3), static_cast<U32>(arg4),
static_cast<U32>(arg5));
break;
case 6:
this->log_FATAL_AF_ASSERT_6(fileArg, static_cast<U32>(lineNo), static_cast<U32>(arg1),
static_cast<U32>(arg2), static_cast<U32>(arg3), static_cast<U32>(arg4),
static_cast<U32>(arg5), static_cast<U32>(arg6));
break;
default:
this->log_FATAL_AF_UNEXPECTED_ASSERT(fileArg, static_cast<U32>(lineNo), static_cast<U32>(numArgs));
break;
}
// Assert processing complete, decrement active assert counter
this->m_assertCount--;
}
} // end namespace Svc