cancel
Showing results for 
Search instead for 
Did you mean: 

sprintf causes hard fault.

Trevor Jones
Senior

I use "sprintf (string,"comment"); everywhere

now for some reason, I am getting a hardfault. in an innocuous print.

length += sprintf(String + length, "Received Packet from ");

length is only 15.

String is declared as

char String[256];

I guess it is using malloc,

How do we check the allocations are being cleared ?

I never use malloc anywhere, so its not me...

21 REPLIES 21
Trevor Jones
Senior

will bypass that code.

berendi
Principal

This smells very badly after a corrupted heap.

Show your _sbrk() function, and set a breakpoint on it to see whether all of its variables make sense, and the heap is where you think it is.

Make sure you don't ever call (s)printf in an interrupt handler.

Check the stack pointer register, does it make sense? If the stack is in DTCM (0x20000000 - 0x2001FFFF), malloc() gets badly confused.

There is a FatFs buffer before the stack. Check FatFs configuration, and make sure the disk i/o function doesn't overflow.

Does the problem go away if you don't use FatFs?

Set errno (the variable sitting between the fatfs buffer and the heap) to a guard value, e.g. 0xDEADBEEF early in main(). See if it ever gets changed when it shouldn't, i.e. returning from a failing library function.

have the newlib with floating point support in printf running.

Yes do use FatFS but can't disable it easily, dont want to break it :(

dont use it currently but it is installed.

have set Stack and Heap to 8K each.

can't find _sbrk function,

can't find the errno variable.

don't ever call sprintf from an interrupt

stack heap was in 0x24000000 now moved to RAMD3 area successfully

trying to clear the new stack/heap area,

cant seem to declare a variable in the .lds file (below the reset routine)

void __attribute__((naked, noreturn)) Reset_Handler()
{
	//Normally the CPU should will setup the based on the value from the first entry in the vector table.
	//If you encounter problems with accessing stack variables during initialization, ensure the line below is enabled.
	#ifdef sram_layout
	asm ("ldr sp, =_estack");
	#endif
 
	void **pSource, **pDest;
	for (pSource = &_sidata, pDest = &_sdata; pDest != &_edata; pSource++, pDest++)
		*pDest = *pSource;
 
	for (pDest = &_sbss; pDest != &_ebss; pDest++)
		*pDest = 0;
	for (pDest = &_heapStart; pDest != &_stackEnd; pDest++)  //my new variables wont compile
			*pDest = 0;
 
	SystemInit();
	__libc_init_array();
	(void)main();
	for (;;) ;
}
 
.heap (NOLOAD) :
	{
		. = ALIGN(4);
		_heapStart =.;
		PROVIDE(__heap_start__ = _heapStart);
		KEEP(*(.heap))
		. = ALIGN(4);
		. = . + 0x2000;
		PROVIDE(__heap_end__ = .);
	} > RAM_D3
 
	.reserved_for_stack (NOLOAD) :
	{
		. = ALIGN(4);
		PROVIDE(__reserved_for_stack_start__ = .);
		KEEP(*(.reserved_for_stack))
		. = ALIGN(4);
		. = . + 0x2000;
		_stackEnd =.;
		PROVIDE(__reserved_for_stack_end__ = _stackEnd);
	} > RAM_D3

currently the Memory area for the stack/heap is full of uninitialized data

set the stack and heap to 16k each, the HardFault still fails at the same point.

can't clear the area..

Look harder for _sbrk. A project using sprintf from newlib doesn't compile without it.

Where did your Reset_Handler come from? You are using HAL, but it's as different as it can be from the Reset_Handler distributed with HAL.

Check the value of the SP register, when entering main() and when things break.

Set errno early in main.

#include <errno.h>
int main() {
    errno = 0xDEADBEEF;
    ...
}

and check whether it's changed, and when.

Trevor Jones
Senior

I am using Visual Studio

will add that include in the morning , at home now

newlib is precompiled, so not looking in there I guess.

the reset handler is installed from the CUBE so HAL based..

please understand this error is only in this place, sprintf works everywhere else without issue.

_sbrk is not part of newlib, it must be provided by the user application. See https://sourceware.org/newlib/libc.html#Syscalls

HAL has Reset_Handler() written in assembly. Yours is written in C, so it doesn't come from Cube.

Your Reset_Handler has the naked attribute, which shouldn't be used for C functions. See https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html

Sorry, I can't help you any further, this stuff is messed up beyond all recognition. Get a sane toolchain.

Trevor Jones
Senior

Thanks for your support,

this code starts from the cube and managed in Visual Studio.

not sure about how it comes together and why they do it like that, but generally very good results. used the cube/VS on F0 F7 H7 on many boards.

I pound sprintf usually, without issue. to CDC and U1 for debug

I have commented out that section and still sprintf works everywhere else..

it just seems a little flaky to me. the code is not on a boundary length is well inside the boundary, not sure what is falling over.

other than this issue, all the ST processors seem very stable.

anyhow, commented it out... everything else is working well.

Do you think I should be implementing a _sbrk ? function how does malloc unload ?

Keep in mind that malloc is broken or FatFs is misconfigured. You can expect arbitrary regions of memory or hardware registers changed anytime. Just remember it the next time you are facing problems with harmlessly looking code.

If there is no _sbrk, programs using newlib malloc explicitly or implicitly (throgh sprintf) could not be compiled at all. Either there is _sbrk() hidden somewhere, or it isn't newlib.

Copying simple strings with sprintf() is a serious waste of cycles, you might want to replace it with strcpy() or strcat()

#include <string.h>
 
    char String[256];
    strcpy(String, "Received Packet from ");
    if (have_LCD)
        strcat(String, "LCD unit ");
    if(have_Facex)
        strcat(String, "Facex unit ");

this will of course not eliminate the problem, just postpone it.

Yes, I can see that  serious waste of cycles,

I made my own string copy today, its a trivial exercise without boundaries just looking for a null, but its always there.

I should add a limit to that.

In Visual Studio, when you make the project, it asks if you want to include the newlib,

I select the newlib with floating point support in printf. probably pre-compiled and why I cannot step into sprintf.

Yes, the issue re-appeared again today in anther innocuous sprintf... hence I made a new one...

nprintf... while (*String) copy bytes; then add the null

but the original question still applies, how can we check the malloc allocation level and if it has a memory leak.

generally, I dont use FatFS at all in a day.

I only use it when an SDCard is installed and I use @Community member​'s  flash burning and reading code for the external QSPI which runs without FatFS

that seems very stable, but once the images are saved in Flash from the SDCard,

FatFS remains unused for the next month.. (although it is initialised at startup.)

so I don't think its FatFS.