Microsoft C library _set_output_format() and threads wtf



  • Recently I had to debug a very large multithreaded C++ application which would crash randomly when it was printing out the contents of arrays of double precision floats into text files. The only clue was that the problem got worse on quad core machines compared with dual-core.

    The output file format expected the numbers to be printed with at least two exponent digits using the %E format specifier. If the exponent required three digits then three would be printed. That is what many C libraries implement.

    Microsoft got the behaviour non-standard in an earlier version  (prior to vcrt8 as far as I can tell)  of their C runtime library, and made %E produce three exponent digits all of the time.

    Later on they provided a fixed version that conforms to standards, and provided the _set_output_format( int format_code ) function to allow users to command the newer library to produce three digits all the time.

    What is not made clear is that this setting is global on the PC for any application using the library. It is not surprising that it is global but it makes it hard to use if multiplied by another wtf:

    What I found was that in our application (our WTF) , the code was constantly toggling the _set_output_format between the two digit and three digit exponent settings  as it printed these double precision floats .

    What was causing the crash was two threads both calling the same formatted print function. One would set the flag to two digits, call into the c library  to format a string and then set the flag to three digits again. The second would do the same but not quite at the same instant on another processor core.

    Inside the library code calculates the string buffer length required to store the string, allocates the memory and then prints the string. What was happening was the other thread would set the global flag to three digit exponents just after the buffer length was calculated for two digit exponents and then the just-allocated buffer would be one character too small when the string was printed with three digits.

    So the C library would bomb with an internally produced and apparently impossible "index out of bounds error", on an object which it had just allocated with adequate space. 

     


  • Garbage Person

     Did you report the frakkin bug? Or are you just going to bitch about it?



  • hate to break it to you, but since it kinda alters the behavior of printf, you're probably going to have to lock it via a critical section or something.

    If it works, a better alternative might be to use a value with the format specifier.  Maybe you can do something like %10.2E where applicable to get 10 total digits, with a precision of 2.  I haven't used the format specifiers with %E alot, but if it works, that could be a solution.


Log in to reply