X-Developer Cross-platform development in C++, Flight Simulation

11May/11Off

snprintf is not _snprintf_s_WTF_SNAFU !

The last three days were filled up with collecting all the customer reports and preparing the first service pack for the CRJ. Luckily, no real showstopper showed up, but one thing was strange:

I was fixing the display of 25kHz spaced COM-frequencies, where the CRJ 1.0.0 software had a stupid rounding error. I implemented the fix on my Linux Notebook, and was satisfied with the result. I pushed the fix to my git repository, pulled on my Windows PC and compiled again. Starting up the CRJ I had an instant crash with the dreaded "X-Plane.exe has stopped working"-window.

What had happened? To display the value on the small RTU display, I use a well-known C99 function called "snprintf()". It is the safe counterpart of sprintf() (Stream print formatted) that takes an additional argument, the maximum number of characters to be written to the destination buffer. What is great about snprintf() is that it guarantees the output buffer is null-terminated, even if when the output is truncated. And that was precisely what I wanted: The output had to be truncated to 7 characters, 3 characters the frequency before the decimal, then the decimal point, then two digits after the decimal, then the null-terminator. If I put in the frequency as 136.375 it should be truncated so the string reads 136.37\0

Fair enough, now why was the CRJ crashing so violently on Windows? The answer is: Visual C++ doesn't have an snprintf() function. There exist the following two "equivalents": _snprintf() and sprintf_s(). The former was what I used - and guess what - the Microsoft _snprintf() does NOT guarantee the null-terminator!!1!

So the frequency on the RTU read something like 136.375!$Dg=73*+#?ยง with some random garbage behind the 7th character.

snprintf() is a C99 standardized function, for god's sake! It's not a GNU extension or a Torvalds memorial function. It's flipping C99 AND C++0x!

Google for the rescue! Apparently quite a lot of people on MSDN have already stumbled over the retarded _snprintf function and there is a workaround that behaves consistent to the C99 requirements:

#ifdef _MSC_VER
#include <cstdarg>
inline int my_snprintf(char* str, size_t size, const char* format, ...)
{
    size_t count;
    va_list ap;
    va_start(ap, format);
    count = _vscprintf(format, ap);
    _vsnprintf_s(str, size, _TRUNCATE, format, ap);
    va_end(ap);
    return count;
}
#define snprintf my_snprintf
#endif

Now that's a kludgy workaround that keeps the CRJ flying...

  • del.icio.us
  • Digg
  • email
  • Facebook
  • Google Buzz
  • Identi.ca
  • MisterWong
  • MySpace
  • Orkut
  • Print
  • Reddit
  • RSS
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
Comments (0) Trackbacks (0)

Sorry, the comment form is closed at this time.

Trackbacks are disabled.