3

So I've got a compiler bug with their low level _fconvert() function that the vendor has marked as low priority, but the effect is that the embedded system will crash if I send a NaN value to a printf() style function. I'd like to write a wrapper for sprintf() that parses for floats, and if they are NaN values, they get replaced by a macro value. I think I get the basics on how to pass the variable parameter list, but not how to parse/replace. Can anyone help me on this?

int no_nan_sprintf(char *target_str, const char *format, ...)
{
    va_list args;

    va_start(args, format);

    //need help here, something like
    int idx;
    for (idx = 0; idx < sizeof(args); idx++)
    {
        if (isnan(args[idx]))
        {
            args[idx] = NAN_SUBSTITUTE_VALUE;
        }
    }

    //this should be tha call I want to make to sprintf
    sprintf(target_str, format, args);
    va_end(args);
}                  /* no_nan_sprintf */
grambo
  • 283
  • 2
  • 10
  • 2
    Good question. This looks tricky to me. Might be worth searching around to see if anyone has done this before. I can't see how you would do this without looking at `format` and *only* changing the arguments pertinent to a `float` or `double`. As an alternative, it might be an idea to adjust all the callers to `printf`; at least at the call sites you know the types. – Bathsheba Sep 07 '17 at 13:09
  • 1
    Maybe this could help: [How to replace values in a va_list](https://stackoverflow.com/questions/38525863/how-to-replace-values-in-va-list). After that use the `vsprintf()` function that takes your `va_list`. – Andre Kampling Sep 07 '17 at 13:18
  • Maybe thos SO question can help: https://stackoverflow.com/questions/570669/checking-if-a-double-or-float-is-nan-in-c – Jabberwocky Sep 07 '17 at 13:30
  • 1
    Without exactly knowing the ABI and code not covered by the standard, this is not possible. A better approach would be to either re-implement `snprintf` and use that or use a fixed library. Ater all , this is not a compiler issue, but the library. As a personal remark: A verndor for a commercial implementation and library not being able to fix such a simple library issue should be considered to be gotten rid of. PIC32 is MIPS and there are free and OSS toolchains and libraries available which don't have this problem (or at least the code can be fixed by the user). – too honest for this site Sep 07 '17 at 13:50
  • @Olaf I'd really like to just rewrite their _fconvert() function, this is where the real headache is. If I rewrite printf(), I also need to rewrite sprintf(), snprintf, etc. ...and I'd probably be on an MSP430 if it were my choice. The MPLAB X developers are currently "heavily involved in adding support for some of our AVR and ARM MCUs" per what they've told me on my support ticket. – grambo Sep 07 '17 at 14:15
  • @grambo: The PIC32 is fine and certainly a larger iron than the MSP430 (more similar to the MSP432, which I'd prefer here, but I'm a bit biased about Atmel anyway). Anyway, for all these platforms you can get free tools. A commercial vendor not being able to delive a standard compliant toolchain is a strict no-go for me. Worse, as the OSS tools (gcc, newlib e.g.) are almost certainly superiour in aspects of code quality and compliance). Just out of curiosity: is that IAR? – too honest for this site Sep 07 '17 at 14:22
  • As you mention MPLAB: yes, They took over Atmel some time ago. But IIRC, they do use gcc, so you just might change their libc to a FOSS one. As a sidenote: using those bloat `printf` family stuff is typically not a good idea on bare-metal embedded anyway (less on the MSP430, btw); you should consider using distinct conversion function which just do what you **really** need and not that heavy-weight parsing stuff. – too honest for this site Sep 07 '17 at 14:25
  • @Olaf speed of development turned out to be more critical than execution speed, we have a lot of slack in this system & code maintainability is critical, so the sprintf() solution was palatable until we found this... I've searched around and there's a lot of dead oss PIC toolchains from 8-12 years ago, do you have an active project you would suggest I try? (target is a PIC32MX) – grambo Sep 07 '17 at 17:37
  • @grambo: I don't use the PIC32 and I don't recommend it to my customers for new developements; with buying Atmel, Microchip has a strong and mostly superior palette of ARM-based MCUs. So IDK, but gcc definitively supports the MIPS platform and IIRC, MPLAB does use it already. For the libs, you should have a look. I don't think there is no support for it. But then I don't use much of the standard library anyway, my projects tsypically don't use much text IO, except for displays and on those printf etc. are near useless anyway. – too honest for this site Sep 07 '17 at 17:49

1 Answers1

1

The nain problem filtering the entire call to *printf would have is that it's not enough to blindly replace all arguments - you need to be able to do this only for floating point parameters.

That means you'll need to intelligently process the format string itself to ensure you don't modify pointers or integers.

In terms of just ensuring not passing NaNs, I'd opt for changing something like:

printf ("Two floats and an int: %f %d %f\n", float1, int1, float2);

with:

float fx(float f) { return isnan(f) ? 0 : f; }
printf ("Two floats and an int: %f %d %f\n", fx(float1), int1, fx(float2));

That way, you don't have to worry about re-implementing all the hard details of the printf family, just filter the specific variables causing trouble. The fx function can be made as complex as needed such as using a macro instead of zero, allowing a default to be provided per-call and so on.

Obviously this will only work if you can change all the calls where NaN is being passed. If they're buried deep within code you don't control, you may well have to go the more difficult route of replacing entire chunks of the standard library.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • I do like it, but I was looking for something that would allow me to replace some 200+ snprintf() statements without having to invasively find, think about and modify each one... – grambo Jun 23 '18 at 06:26