# Semaphore Aquire leads to hardFault

**URL:** <https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802>\
**Category:** Kernel\
**Created:** [June 22, 2024, 7:13pm UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802 "2024-06-22T19:13:58Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![kapouchima](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/kapouchima/32/4722_2.png) [@kapouchima](https://forums.freertos.org/u/kapouchima)\
**Post date:** [June 22, 2024, 7:13pm UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/1 "2024-06-22T19:13:59Z")

</div>

Hi,  
After my program runs for some time it suddenly stops on a HardFault. Checking the call stack seems like the xQueue is corrupted but the original SemaphoreId passed in is correct and not corrupted. I don’t get how it is even possible.  
Semaphore is defined statically and configASSERT is enabled.

```auto
static struct
{
  LOG_Transmitter txHandler;
  osSemaphoreId_t logTxSemId;
  char buffer[LOG_BUFFER_LEN];
} obj;

static const char* LogTypeToStr(uint8_t type)
{
  ...
}

void LOG(const char* file, uint16_t line, uint8_t type, const char* fmt, ...)
{
#if (LOG_ENABLE != 0)
  if ((obj.txHandler != NULL) && (fmt != NULL))
  {
    va_list args;
    va_start(args, fmt);
    osSemaphoreAcquire(obj.logTxSemId, osWaitForever);
    snprintf(
      obj.buffer, LOG_BUFFER_LEN, "%010ld\t[%s]\t%s:%d ", osKernelGetTickCount(), LogTypeToStr(type), file, line);
    vsnprintf(&obj.buffer[strlen(obj.buffer)], LOG_BUFFER_LEN - strlen(obj.buffer), fmt, args);
    snprintf(&obj.buffer[strlen(obj.buffer)], LOG_BUFFER_LEN - strlen(obj.buffer), "\r\n");
    va_end(args);

    obj.txHandler(obj.buffer, strlen(obj.buffer));
  }
#endif
}

void LOG_init(LOG_Transmitter tx)
{
  obj.txHandler = tx;
  static StaticSemaphore_t semCtb;
  static osSemaphoreAttr_t logTxSemAttr = {.name = "LogTxSem", .cb_mem = &semCtb, .cb_size = sizeof(semCtb)};
  obj.logTxSemId = osSemaphoreNew(1, 1, &logTxSemAttr);
}

void LOG_txDone(void)
{
  osSemaphoreRelease(obj.logTxSemId);
}

```

 ![image](https://d2v6vdsk2p900z.cloudfront.net/original/2X/9/94e5b94efe4b98ebb996a6ad1ac1a7f9233ebfbc.png)

pxQueue is 0x2 which is not a correct address but why reading it leads to HardFault is still a another weird thing.

NOTE. MCU is a CortexM0 so all interrupts are disable regardless of priorities in critical section I assume

---

<div class="post-metadata">

**Author:** ![hs2](https://avatars.discourse-cdn.com/v4/letter/h/a4c791/32.png) [@hs2](https://forums.freertos.org/u/hs2)\
**Post date:** [June 23, 2024, 6:33am UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/2 "2024-06-23T06:33:52Z")

</div>

Did you also enable [FreeRTOS - stacks and stack overflow checking](https://www.freertos.org/Stacks-and-stack-overflow-checking.html?_ga=2.62741866.775324228.1716880857-1295978378.1669191309) ?  
Is `LOG` only called from tasks and not from ISRs ?  
Seems there is a memory corruption maybe due to stack overflow (or a call in an ISR).

In addition since you need to protect the log `obj` you should use an `osMutex` instead of a semaphore.  
Also you should avoid excessive calls to (costly) `strlen` and just use the return value of the printf-functions :

```auto
…
int len = snprintf(obj.buffer, LOG_BUFFER_LEN, "%010ld\t[%s]\t%s:%d ", osKernelGetTickCount(), LogTypeToStr(type), file, line);
    len += vsnprintf(&obj.buffer[len], LOG_BUFFER_LEN - len, fmt, args);
    len += snprintf(&obj.buffer[len], LOG_BUFFER_LEN - len, "\r\n");
    va_end(args);

    obj.txHandler(obj.buffer, len);

```

---

<div class="post-metadata">

**Author:** ![kapouchima](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/kapouchima/32/4722_2.png) [@kapouchima](https://forums.freertos.org/u/kapouchima)\
**Post date:** [June 23, 2024, 8:56am UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/3 "2024-06-23T08:56:27Z")

</div>

The `configCHECK_FOR_STACK_OVERFLOW` is set to 2 and no overflow is detected. Also I can check from the XRTOS data that every task has enough all time low free space in it’s stack. On the other hand it seems like the semaphore integrity is intact from the memory snapshot I attached in the original post.

LOG is used from various places but it’s not called from ISR. Also CMSIS wrapper for acquiring semaphore handles the API calls from ISR.

 ![image](https://d2v6vdsk2p900z.cloudfront.net/original/2X/d/d447514a857ea5d0db26fcd73bfe91daa8891085.png)

---

<div class="post-metadata">

**Author:** ![hs2](https://avatars.discourse-cdn.com/v4/letter/h/a4c791/32.png) [@hs2](https://forums.freertos.org/u/hs2)\
**Post date:** [June 23, 2024, 9:22am UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/4 "2024-06-23T09:22:38Z")

</div>

Note that various FreeRTOS calls and also the CMSIS wrappers like `osSemaphoreAcquire` provide return values indicating success or error.  
You should check them to see if the desired operation was done as expected.

---

<div class="post-metadata">

**Author:** ![kapouchima](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/kapouchima/32/4722_2.png) [@kapouchima](https://forums.freertos.org/u/kapouchima)\
**Post date:** [June 23, 2024, 9:30am UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/5 "2024-06-23T09:30:05Z")

</div>

Sure, but in this specific case it shouldn’t lead to a crash. If API returns with error it would try to send data on an already busy bus and it would fail in HAL layer

---

<div class="post-metadata">

**Author:** ![hs2](https://avatars.discourse-cdn.com/v4/letter/h/a4c791/32.png) [@hs2](https://forums.freertos.org/u/hs2)\
**Post date:** [June 23, 2024, 9:55am UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/6 "2024-06-23T09:55:20Z")

</div>

And could corrupt the `obj` data etc. More important is that the root cause problem for the memory corruption probably happened somewhere else and/or earlier.  
Hence you should try to write robust code and that starts with checking (error) return values where possible or do a `configASSERT` at least.

---

<div class="post-metadata">

**Author:** ![kapouchima](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/kapouchima/32/4722_2.png) [@kapouchima](https://forums.freertos.org/u/kapouchima)\
**Post date:** [June 23, 2024, 10:28am UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/7 "2024-06-23T10:28:06Z")

</div>

Refactored log as you suggested. Also ConfigASSERT is implemented.

```auto
void LOG(const char* file, uint16_t line, uint8_t type, const char* fmt, ...)
{
#if (LOG_ENABLE != 0)
  if ((obj.txHandler != NULL) && (fmt != NULL))
  {
    va_list args;
    va_start(args, fmt);
    if (osSemaphoreAcquire(obj.logTxSemId, osWaitForever) != osOK)
    {
      goto error;
    }

    int32_t len = snprintf(
      obj.buffer, LOG_BUFFER_LEN, "%010ld\t[%s]\t%s:%d ", osKernelGetTickCount(), LogTypeToStr(type), file, line);

    if (len < 0)
    {
      goto error;
    }

    {
      int32_t newLen = vsnprintf(&obj.buffer[len], LOG_BUFFER_LEN - len, fmt, args);
      if (newLen < 0)
      {
        goto error;
      }
      len += newLen;
    }

    {
      int32_t newLen = snprintf(&obj.buffer[len], LOG_BUFFER_LEN - len, "\r\n");
      if (newLen < 0)
      {
        goto error;
      }
      len += newLen;
    }
    va_end(args);

    obj.txHandler(obj.buffer, len);
  }
error:
#endif
}

void LOG_init(LOG_Transmitter tx)
{
  obj.txHandler = tx;
  static StaticSemaphore_t semCtb;
  static osSemaphoreAttr_t logTxSemAttr = {.name = "LogTxSem", .cb_mem = &semCtb, .cb_size = sizeof(semCtb)};
  obj.logTxSemId = osSemaphoreNew(1, 1, &logTxSemAttr);
}

void LOG_txDone(void)
{
  osSemaphoreRelease(obj.logTxSemId);
}

```

Still I’m not sure if the crash is due to memory corruption

---

<div class="post-metadata">

**Author:** ![hs2](https://avatars.discourse-cdn.com/v4/letter/h/a4c791/32.png) [@hs2](https://forums.freertos.org/u/hs2)\
**Post date:** [June 23, 2024, 11:34am UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/8 "2024-06-23T11:34:10Z")

</div>

> [@kapouchima](#):
>
> `osSemaphoreAcquire`

and consider to use the better suited `osMutex` because you want/have to mutual exclude multiple `LOG` callers (with priority inheritance).  
I still think it is a memory corruption (in fact a corruption of the FreeRTOS internal semaphore data structure with the symptom that the queue handle is damaged).  
Beware that this probably happened somewhere else in your code. The `LOG` code is pretty straight forward and seems ok so far. Try to review and maybe improve your remaining application code in a similar way and try to narrow it down by excluding code parts. Also HAL can be buggy…  
It might help if you can apply a data breakpoint at the queue handle member of the semaphore/mutex structure if supported by your debugger. Then you could trap an unwanted access/overwrite of it.  
BTW do you have dynamic memory allocation enabled ? If yes, which heap implementation is used ?

---

<div class="post-metadata">

**Author:** ![kapouchima](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/kapouchima/32/4722_2.png) [@kapouchima](https://forums.freertos.org/u/kapouchima)\
**Post date:** [June 23, 2024, 1:10pm UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/9 "2024-06-23T13:10:08Z")

</div>

Tx handler uses DMA and it’s calling the `LOG_txDone` from ISR. That’s why Mutex is not used.

Some USB libraries from ST is using dynamic allocation but all RTOS components from my code is using static allocation, heap1 algorithm is used.

---

<div class="post-metadata">

**Author:** ![hs2](https://avatars.discourse-cdn.com/v4/letter/h/a4c791/32.png) [@hs2](https://forums.freertos.org/u/hs2)\
**Post date:** [June 23, 2024, 1:19pm UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/10 "2024-06-23T13:19:49Z")

</div>

Hopefully you don’t have a problem with the ST USB stack like [STM32-RTOS-USB-HowToFix/README.md at master · gmgunderground/STM32-RTOS-USB-HowToFix · GitHub](https://github.com/gmgunderground/STM32-RTOS-USB-HowToFix/blob/master/README.md) or other 3rd party code.  
Good luck !

---

<div class="post-metadata">

**Author:** ![kapouchima](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/kapouchima/32/4722_2.png) [@kapouchima](https://forums.freertos.org/u/kapouchima)\
**Post date:** [June 23, 2024, 9:48pm UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/11 "2024-06-23T21:48:53Z")

</div>

After spending days to debug the issue I finally found the root cause:

Steps taken:

- Blaming myself for memory/stack overflows
- Tried heap4, heap1 and newlib for memory allocation
- Refactoring all RTOS components using static allocation
- Tracing all the failed RTOS structs in memory and couldn’t find any corruption
- Enabling configASSERT, stack monitor and RTOS structs integrity check with no luck

Finally with some luck came across `https://forums.freertos.org/t/hardfault-on-arm-cortex-m0/15423/11` and check the errata sheet for my MCU (same MCU as the post) and YES! cross prefetching instruction from different banks of Flash leads to corruption of CPU registers/context sometimes. Thats why passed struct address and contents to an API was fine but then inside the API r0 was 0 instead of a correct pointer. (This should be fraud since ST sells the chip as a 256K flash MCU and practically you can’t have a bigger than 128K single application on it! or you should disable the prefetch)

I had a bootloader at the beginning of first bank and the application code was spilled to second bank of the flash.

Fix: linked the bootloader to bank1 and the app to bank2 and now it works reliably.

@hs2 Thanks for your time and help

---

<div class="post-metadata">

**Author:** ![aggarg](https://d3iykfbgfh8zhg.cloudfront.net/user_avatar/forums.freertos.org/aggarg/32/4245_2.png) [@aggarg](https://forums.freertos.org/u/aggarg)\
**Post date:** [June 24, 2024, 5:57am UTC](https://forums.freertos.org/t/semaphore-aquire-leads-to-hardfault/20802/12 "2024-06-24T05:57:18Z")

</div>

Thank you for sharing your solution!
