uxCriticalNesting has incorrect count in PortExitCritical called from xQueueGenericSend

One of our users is getting an assertion failure in PortExitCritical, because uxCriticalNesting is zero but it shouldn’t be. The assertion comes from line 423 of file FreeRTOS\src\portable\GCC\ARM_CM4F/portmacro.h which reads:

void vPortExitCritical( void )
configASSERT( uxCriticalNesting ); //<<<< This line

The stack at the point of the assertion has return addresses in the following functions:

our own code that calls xQueueGiveMutexRecursive

Has anyone any idea what could cause this? uxCriticalNesting is incremented (via taskENTER_CRITICAL()) earlier in xQueueGenericSend, so it should be impossible for it to be zero at that point.

This topic uxCriticalNesting has incorrect count in PortExitCritical, in 2 different threads sounds similar, however there is no resolution listed for that thread.

The version of FreeRTOS is 10.0.0 although confusingly it has #define tskKERNEL_VERSION_NUMBER “V9.0.0” in tasks.h (but the header comment says 10.0.0).

As this is happening within the queue API function, so we know the uxCriticalNesting variable should not be zero, my first assumption is that the variable is simply getting corrupted (overwritten) somewhere. As this in this case the queue is being used as a mutex it cannot be copying the data into the queue that causes the corruption as mutexes are zero bytes long, so no data is actually copied. It could just be an old fashioned stack overflow - do you have configCHECK_FOR_STACK_OVERFLOW set to 2? Another possibility is a corruption caused by incorrect interrupt priority assignments - if a FreeRTOS API function is used from an interrupt that has a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY then it will breach the critical section an bad things can happen. Do you have configASSERT() defined? Have you checked through these pages? https://www.freertos.org/FAQHelp.html https://www.freertos.org/RTOS-Cortex-M3-M4.html

Hi Richard, thanks for your response.

  • configCHECK_FOR_STACK_OVERFLOW is set to 2
  • configASSERT is defined as “if( ( x ) == 0 ) vAssertCalled( LINE, FILE )” and vAssertCalled calls our crash handler, which dumps the parameters, system registers and part of the stack to flash, then resets the MCU. That’s how I knew an assertion was failing and was able to trace the file/line and the call stack.
  • I am aware of the importance of configMAX_SYSCALL_INTERRUPT_PRIORITY, not calling non-ISR FreeRTOS functions from ISRs, and only calling the ISR FreeRTOS function from ISRs with a low enough interrupt priority. On the occasions during development when we have violated these rules, the assert mechanism has reported that to us very efficiently!

We have been using FreeRTOS in this open source software since June 2018. We have tens of thousands of users running this firmware family, and only one of them is getting this issue. In case it is a hardware issue, we’ll try swapping the hardware next.