C Library Re-entrancy/Thread-Safety
I hate to bring this topic up again, but I'm still having issues I can't explain and weren't answered by my previous inquiry.
Does setting the "Use Multi Threaded Libraries" to "Yes" affect the thread-safety of the underlying floating point math functions? For example, if I'm using doubles and floats in my code, but with the Cortex-M4 hardware FPU disabled, does the compiler generate calls to library code to perform floating division, multiplication, etc. that are thread safe?
I'm seeing issues running a multi-threaded application that can only be reasonably explained by the context of one task getting corrupted by another. If I don't use any floating point in these threads, the problem doesn't happen.
If I compile and run the exact same code under LPCXpresso, I don't see this thread corruption.
I suppose I could switch to using LPCXpresso for this application, but I'd much rather use CrossWorks.
-
Okay, here's some more info:
I whittled my code down to the bare minimum necessary to reproduce this issue. The offending line of code is this one:
sprintf(cptr, "%3.2f\r", z);
The variable "z" is declared as a double auto variable in the function containing the sprintf(). cptr is declared as an auto "uint8_t cptr[40]". When this line executes, an unrelated global variable in my app is corrupted. It's corrupted by the C library routine __putc (called from vfprintf, which is called from sprintf). I have interrupts disabled before executing this code (by setting PRIMASK to 1) to prevent any interrupt handlers from running.
I have the project properties set as follows:
Treat double as float: No
Include standard libraries: Yes
Library optimization: Fast
Use GCC libraries: Yes
Printf floating point supoprted: Yes
Use multithreaded libraries: Yes or No (it doesn't matter--the issue occurs no matter what this is set to)
I have the Cortex-M4 hardware FPU disabled. I have it disabled in the properties as well, and the compiler is not generating any floating point instructions, nor are there any in the libraries.
What's going on here? Why is this call to sprintf corrupting an unrelated global variable in my application?
-
Well, I found why sprintf was corrupting another variable: it was generating more character output than the string could hold.
I changed the sprintf to a snprintf and limited the output size to less than the size of the character array passed as the first parameter and this fixed the corruption of the global variable problem.
Now the question becomes "why does snprintf generate wrong results?" For example, when I print the string generated by the following code
uint8_t cptr[82];
snprintf(cptr, 80, "z=%f\r", 3.14159);
I get:
z=-106833101327820180000000000000000000000000000000000000000000000000000000000000
which is clearly bogus. I get the same result if I do
snprintf(cptr, 80, "z=%f\r", (double)3.14159);
or
double z = 3.14159;
snprintf(cptr, 80, "z=%f\r", z);
As I mentioned in a previous comment, I do have "Printf Floating Point Supported" set to "YES" in the properties of my project.
-
Ah, I see that somewhere in the CrossWorks 3.x series you switched the default C compiler from gcc to clang. If I change my project properties to use gcc instead of clang, snprintf works as expected and I get "z=3.141590" on the output.
I would actually prefer to use clang. What libraries do I need to specify when using it to get snprintf to work properly? I've already tried setting "Use GCC Libraries" to both YES and NO and that doesn't seem to affect the problem I'm seeing with snprintf when my code is compiled with clang.
I'm using CrossWorks 3.2 by the way. I haven't updated to 3.3 yet.
Please sign in to leave a comment.
Comments
12 comments