sprintf %f corrupts stack

dnadler wrote on Monday, December 26, 2016:

I’m not sure this is a FreeRTOS problem, but…
Cortex M4F (Kenetis K64), gcc, nano, newlib with float.
Only one task uses floating point; no issues there.
A sprintf of a floating point number returns the correct string but corrupts the stack.
The corruption is miles away from the top of the stack.
FreeRTOS-aware debug says I have several kb of extra stack space for this task.
Absolutely reproducible; this corrupts stack: sprintf(out.pBuffer,“floatOutTest=%f”, 1.2345f);
The buffer is in the right place and printing decimal values works fine.
Thanks in advance for any ideas!
Best Regards, Dave

rtel wrote on Tuesday, December 27, 2016:

Things to check:

  1. The stack is 8 byte aligned at the point sprintf() is called (put a breakpoint on the call to sprintf() and check the value of the stack pointer in the debugger).

  2. Are you using a FreeRTOS heap memory allocator other than heap_3.c? If so, check sprintf() is not calling malloc(). heap_3.c is the only FreeRTOS memory allocator that will need malloc() to be configured correctly, and if it is not configured and sprintf() attempts to call it then anything could happen. Probably the easiest way to check this is to provide your own implementation of malloc() that does nothing but contain an NOP instruction, or trigger an assert, then put a break point in your implementation of malloc() and see if it is ever called.

dnadler wrote on Tuesday, December 27, 2016:

Stack alignment is AOK. I’m using your heap_4. Per your suggestion I added a dummy malloc with asm bkpt, and sure enough the damn thing is calling malloc:
** sprintf -> _svprintf_r -> _printf_float -> cvt -> _dtoa_r -> malloc **
Unfortunately I don’t have a library built with debug info. I suspect malloc is incorrectly set up by NXP/Freescale (dubious linker script with partioned M4F RAM) and/or its run out of the standard RTL heap’s memory. I could try stubbing it out with heap_4…
Thanks for the help!
Best Regards, Dave

dnadler wrote on Wednesday, December 28, 2016:

Update: Several nano newlib RTL functions (sprintf, strtok) unexpectedly used malloc() or _malloc_r().

The default heap from Freescale/NXP was set to 1kB (for a processor with 256kB RAM!), and the RTL overflowed the heap without halting and corrupted memory. Very Nice!

Do you guys have a replacement for the nano free storage functions that map to FreeRTOS heap functions, to give a single, debuggable pool? Ideally with hard stop on overrun? Is this a bad idea? Should I write this?

Thanks as always,
Best Regards, Dave

rtel wrote on Wednesday, December 28, 2016:

You can provide your own doing something simple such as:

void *malloc( size_t xBytes )
     return pvPortMalloc( xBytes );

void free( void *pvBuffer )
     vPortFree( pvBuffer );

The configASSERT() calls in pvPortMalloc() and vPortFree() will then
work as normal. If you are using GCC (and maybe other compilers) then
there is a way of redirecting these calls using the command line - but
its probably easier and more portable just to add the above functions
into your code.

dnadler wrote on Wednesday, December 28, 2016:

If I understand correctly, its a bit more complicated, as there is a whole family of heap routines included in newlib, and used within newlib. One example above is _malloc_r(). See newlib’s malloc.c source for the entire set. No?

richard_damon wrote on Wednesday, December 28, 2016:

One issue I have seen with some Librararies is they assume the heap can grow up to the stack, and once the kernal is started, the memory map is no longer what they expect. Sometimes using the heap prior to starting the kernal can help. I would make everything use the same heap either like posted above or making FreeRTOS use the libary heap (adding the needed code to make the library heap thread safe).

ammaree wrote on Thursday, January 05, 2017:

Maybe a suggestion to have a look at a complete [v/s/n/f]printf replacement on github. I uses no dynamic memory, supports floats and have a large number of optional extension that can be useful in an embedded environment.

The supported functions can be selected at compile time to minimise the stack space used.
Stack usage is completely predictable with no recursion.

The printf functionality relies ()to some extent) on 2 additional modules also there namely x_time.c and x_string_general.c, so scratch around…

Have a look at https://github.com/ksstech/support_common and shout if you have queries or suggestions, but it is fairly well documented in the source code.

dnadler wrote on Sunday, February 26, 2017:

Thanks Andre for the suggestion.

Richard, can you point me at a replacement for newlib’s malloc and friends, that properly uses FreeRTOS heap functions and reentrancy structures?

Best Regards, Dave

richarddamon wrote on Monday, February 27, 2017:

I just downloaded the newlib-nano repository itself and added the defines used to enable the reentrancy callls. These then call functions __malloc_lock and __malloc_unlock which can just call the scheduler suspend/resume functions like in heap_3.c

I will need to get the exact repository address and files from work tomorrow. The queston comes to what options were the library compiled with, if it was compiled with full re-entrancy endabled, you may just need to define the __malloc_lock/__malloc_unlock functions.

hs2sf wrote on Monday, February 27, 2017:

Alternatively you could make use of the ‘wrap symbol’ linker feature e.g. let the linker replace all ‘malloc’ symbols with (your) __wrap_malloc implementation etc.
You might even implement your own low level _sbrk function.
(I’ve also overloaded the global new/delete operators with ‘noexcept’ versions to safe some code space.)
Good luck, HS2

richarddamon wrote on Thursday, March 02, 2017:

The newlib repository is at sourceware.org

In my case, the enviroment was already using newlib-nano, the package just wasn’t quite configured the way I needed. The use of newlib-nano seems fairly common if you have a gcc based development tool.

If so, first I would see if it is configured to use the interlock functions already. See if a __malloc_lock() / __malloc_unlock functions stubs are already being used. If they are, you just need to define the lock function to call vTaskSuspendAll() and the unlock to call vTaskResumeAll() (and then test that these are called by malloc) and you are set.

If not, you can just add the source code for the malloc module (newlib/libc/stdlib/nano-mallocr.c) to your project. There are other files malloc.c and mallocr.c too that you don’ need (malloc.c is a stub to allow newlib to have reentrant routines, including malloc, and mallocr.c is a ‘big machine’ version of the reentrant malloc).

If your library isn’t based on newlib, you could still look at the newlib version to build a malloc for your self, but check if your library malloc does the work or if it just forwards to some other function.

dnadler wrote on Saturday, July 01, 2017:

Here’s what I finally ended up doing to sort the above problem:
Thanks again for the help!
Best Regards, Dave

heinbali01 wrote on Sunday, July 02, 2017:

Hi Dave, thanks a lot for all these insights!

I just want to confirm that the [v][s][n]printf() implementation in the FreeRTOS Labs TCP/IP ( attached below ) is quite complete and well tested. Unfortunately is misses the floating point formats ( %f, %e, %g, %E, %G ).

These printf() functions only use stack ( about 70 bytes ) and they don’t use the heap.

They are thread- and even interrupt-safe.

I added two formats, to print IPv4 and IPv6 addresses :

    /* Dot notation for IP addresses: */

    printf( "IP = %xip\n", 0xC0A80164 );
    /* will produce "IP =\n" */

    printf( "IP = %pip\n", pxIPv6_Address );
    /* 'pxIPv6_Address' is a pointer to a 16-byte array.
	It could produce "IP = fe80::1\n" */

Memory protection:
Printing a string with %s may lead to a crash in case you make a mistake with the parameters.
The functions in printf-stdarg.c will check the validity of the pointer by calling :

 * Return 1 for readable, 2 for writeable, 3 for both.
 * Function must be provided by the application.
extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress );

Another habit of printf-stdarg.c is to use an external function to actually write the character to a peripheral.

The function below is called in case sprintf(NULL, xxx) is called. We kept it for backward compatibility.

void vOutputChar( const char cChar, const TickType_t xTicksToWait  )
	/* Eg. send a byte to the UART. */

dnadler wrote on Sunday, July 02, 2017:

Thanks Hein, I updated web page to note some of this,
Best Regards, Dave