Skip to main content
MButsch
Associate III
June 28, 2021
Question

Why are calls to strcat() not actually calling strcat()? (and why do I sometimes get a Hard Fault)

I am using STM32CubeIDE v1.6.1 and am seeing some strangeness.

When I call strcat(), I get a hardfault if the end of the string (where the nul is) being catted to is at an odd address?

Here is code from the .list file:

		 char s1[20];
		 strcpy(s1, "--");
 800ab50:	f107 030c 	add.w	r3, r7, #12
 800ab54:	4a65 	ldr	r2, [pc, #404]	; (800acec <sd_cmdproc_process_packet+0x374>)
 800ab56:	6812 	ldr	r2, [r2, #0]
 800ab58:	4611 	mov	r1, r2
 800ab5a:	8019 	strh	r1, [r3, #0]
 800ab5c:	3302 	adds	r3, #2
 800ab5e:	0c12 	lsrs	r2, r2, #16
 800ab60:	701a 	strb	r2, [r3, #0]
		 strcat(s1, "1");
 800ab62:	f107 030c 	add.w	r3, r7, #12
 800ab66:	4618 	mov	r0, r3
 800ab68:	f7f5 fbc4 	bl	80002f4 <strlen>
 800ab6c:	4603 	mov	r3, r0
 800ab6e:	461a 	mov	r2, r3
 800ab70:	f107 030c 	add.w	r3, r7, #12
 800ab74:	4413 	add	r3, r2
 800ab76:	495e 	ldr	r1, [pc, #376]	; (800acf0 <sd_cmdproc_process_packet+0x378>)
 800ab78:	461a 	mov	r2, r3
 800ab7a:	460b 	mov	r3, r1
 800ab7c:	881b 	ldrh	r3, [r3, #0]
 800ab7e:	8013 	strh	r3, [r2, #0]
		 strcat(s1, "2");
 800ab80:	f107 030c 	add.w	r3, r7, #12
 800ab84:	4618 	mov	r0, r3
 800ab86:	f7f5 fbb5 	bl	80002f4 <strlen>
 800ab8a:	4603 	mov	r3, r0
 800ab8c:	461a 	mov	r2, r3
 800ab8e:	f107 030c 	add.w	r3, r7, #12
 800ab92:	4413 	add	r3, r2
 800ab94:	4957 	ldr	r1, [pc, #348]	; (800acf4 <sd_cmdproc_process_packet+0x37c>)
 800ab96:	461a 	mov	r2, r3
 800ab98:	460b 	mov	r3, r1
 800ab9a:	881b 	ldrh	r3, [r3, #0]
 800ab9c:	8013 	strh	r3, [r2, #0]
 800ab9e:	e1c4 	b.n	800af2a <sd_cmdproc_process_packet+0x5b2>
 }

the strcat of "1" works, but the strcat of "2" hard faults. I suspect it isalignment error with the "strh".

It is also curious that the calls to strcat() (and strcpy()) do not call the actual functions.

I appologize if I have missed something obvious.

Thanks,

mark

This topic has been closed for replies.

13 replies

Tesla DeLorean
Guru
June 28, 2021

Are you using a Cortex-M0(+) processor?

Sometimes these calls are folded inline or use intrinsics.

Most Cortex can handle unaligned 16 or 32-bit access, all will fail with LDRD/STRD

Optimization

Correct Core Selection for compiler/libraries

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
MButsch
MButschAuthor
Associate III
June 28, 2021

Guess I should have included that information at the start...

This project is using a Cortex-M7 (STM32F769NIHx) on the STM32F769I-DISCO board.

Here are the gcc options shown in Properties->C/C++ Build->Settings->MCU GCC Compiler->All Options:

-mcpu=cortex-m7 -std=gnu11 -g3 -DDEBUG -DUSE_HAL_DRIVER -DSTM32F769xx -c -I../Core/Inc -I../Drivers/STM32F7xx_HAL_Driver/Inc -I../Drivers/STM32F7xx_HAL_Driver/Inc/Legacy -I../Middlewares/Third_Party/FreeRTOS/Source/include -I../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM7/r0p1 -I../Drivers/CMSIS/Device/ST/STM32F7xx/Include -I../Drivers/CMSIS/Include -I"C:\Users\mbutsch\STM32CubeIDE\workspace_1.6.1\F769-FlashFS\synlib\Inc" -I"C:\Users\mbutsch\STM32CubeIDE\workspace_1.6.1\syntalk\c" -I../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage --specs=nano.specs -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb

Tesla DeLorean
Guru
June 28, 2021

I've posted a couple of Hard Fault Handlers that output actionable data. Interested in a full register complement, and fault location.

I'm not sure the STRH will fail inherently due to an odd address, make sure the strlen() hasn't failed due to missing NUL

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
MButsch
MButschAuthor
Associate III
June 28, 2021

where have you posted Hard Fault Handlers? They may be better than what I have in place currently.

waclawek.jan
Super User
June 28, 2021

> the strcat of "1" works, but the strcat of "2" hard faults.

How do you know?

> FreeRTOS

What about stack overflow?

JW

MButsch
MButschAuthor
Associate III
June 28, 2021

when I singlestep (instruction mode) through the code, inspecting the variable s1....

strcpy(s1, "--"); yields s1 == "--"

strcat(s1, "1"); yields s1 == "--1"

strcat(s1, "2"); yields hard fault when it executes 'strh r3, [r2, #0]'

here are registers after hard fault

pulFaultStackAddress	uint32_t *	0x20002390 <ucHeap+5360>	
r0	volatile uint32_t	0x3 (Hex)	
r1	volatile uint32_t	0x801d45c (Hex)	
r2	volatile uint32_t	0x200023cf (Hex)	
r3	volatile uint32_t	0x32 (Hex)	
r12	volatile uint32_t	0xa (Hex)	
lr	volatile uint32_t	0x800adb3 (Hex)	
pc	volatile uint32_t	0x800adc4 (Hex)	
psr	volatile uint32_t	0x21000000 (Hex)	

waclawek.jan
Super User
June 28, 2021

> pc volatile uint32_t 0x800adc4 (Hex)

That's not in the region you provided the disasm for above.

0x200023cf is in DTCM. Cortex-M7 should allow unaligned accesses there, unless you've set that area as Device or Strongly Ordered in MPU, or you've disabled unaligned accesses generally by setting SCB_CCR.UNALIGN_TRP.

JW

MButsch
MButschAuthor
Associate III
June 29, 2021

OK, so I have resolved it.

In tracking down the Hard Fault, the Usage Fault Status Regsiter indicated it was UNALIGNED.

So I disabled trapping of unaligned accesses by setting the UNALIGN_TRP bit in the CCR to 0. Now it does not Hard Fault.

However, WHY does it generate code like this? And using STM32CubeIDE, is there a way to prevent it from generating code like this?

waclawek.jan
Super User
June 29, 2021

AFAIK SCB_CCR.UNALIGN_TRP is 0 by default after reset for Cortex-M7. So you must have enabled it in your code - startup code, library, whatever.

That's also why compilers work with the default assumption that unaligned accesses are mostly OK for the Cortex-M7 - and, IMO, having unaligned accesses is a major relief in most of the cases.

If you insist on having strictly aligned code, you can try gcc's -mno-unaligned-access switch.

JW

MButsch
MButschAuthor
Associate III
June 29, 2021

thank you for the discussion.

This is my first time using an STM32F7 and the first time I have had to delve this deep in an STM32 part. Lots to learn.

My project was started by selecting the  STM32F769I-DISCO board from the new project selector and having it generate the .ioc file and code.

If the generated code is setting the SCB_CCR.UNALIGN_TRP bit, I have been unable to find where. I searched the project and didn't find anything.

I set a breakpoint at "Reset_Handler:" in startup_stm32F769nihx.s (thinking that this is where execution will start and the SCB_CCR.UNALIGN_TRP is already set there (inspecting in the SFR tab). So I am not sure how/where that bit gets set.

If the default behavior of STM32CubeIDE is to configure checking for aligned accesses, then why does it generate code that will fault? Does anyone know WHY it generates code like this?

Thanks,

Mark

Tesla DeLorean
Guru
June 29, 2021

The "compiler" doesn't know what address any given piece of data or code will be assigned, the "linker" often has more control of that, although it's only party to the details given to it.

In the general case unaligned 16 and 32-bit access is safe. The compiler/optimizer tend to assume this as it yields faster/smaller code.

Might want to look at code generation settings for the Cortex-M0 as that is very unforgiving.

Most of the Cortex-Mx give me headaches with unaligned (byte aligned) data structures in files or serial streams, 64-bit word (doubles) being a particular issue. Although this is still less tedious than the old ARM7 and ARM9, and cases where people wanted to port x86 C code

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..