From: CoolShell
Link: https://coolshell.cn/articles/5388.html
Original: https://www.elpauer.org/2011/08/the-most-stupid-c-bug-ever/
This article is based on “The most stupid C bug ever” and is quite interesting, so I am sharing it with everyone.
I believe that even if you are an expert, you could make such a bug. Let’s take a look at the bug made by the author.
First, the author wanted to create a file with a piece of code. If there is a filename, it creates a real file; if not, it calls tmpfile() to create a temporary file.
This piece of code is part of an HTTP download program in C. code==200 is the HTTP return code.
else if (code == 200) { // Downloading whole file
/* Write new file (plus allow reading once we finish) */
g = fname ? fopen(fname, "w+") : tmpfile();
}
However, this program only works on Unix/Linux because Microsoft’s implementation of tmpfile() chooses C:\ as the directory for temporary files, which poses a big problem for those without administrator privileges. Even on Windows 7, there can be issues even if you have administrator privileges.
Therefore, the above program needs to handle this differently on the Windows platform and cannot directly use the Windows tmpfile() function.
So the author noted this issue and wrote a FIXME in the comments:
else if (code == 200) { // Downloading whole file
/* Write new file (plus allow reading once we finish) */
// FIXME Win32 native version fails here because
// Microsoft's version of tmpfile() creates the file in C:\
g = fname ? fopen(fname, "w+") : tmpfile();
}
Then, the author thought it was necessary to write a cross-platform version:
FILE * tmpfile ( void ) {
#ifndef _WIN32
return tmpfile();
#else
//code for Windows;
#endif
}
Then, the author felt that this implementation was not good and would lead to name conflicts, as this function became too ugly.
So he refactored his code—writing his own implementation of tmpfile() called w32_tmpfile, and then using a macro definition to rename this function to tmpfile() on Windows. (Note: This usage is a standard way of writing cross-platform code.)
#ifdef _WIN32
#define tmpfile w32_tmpfile
#endif
FILE * w32_tmpfile ( void ) {
//code for Windows;
}
Done! Compile the program and run it.
What the heck! It didn’t call my w32_tmpfile(). What’s the problem? Debugging, step by step, and indeed it was not called!
Could it be an issue with the ternary operator? Changing it to an if-else statement worked!
if(NULL != fname) {
g = fopen(fname, "w+");
} else {
g = tmpfile();
}
The ternary operator shouldn’t have a problem, could it be that our macro doesn’t work with the ternary operator? Is this a bug in the compiler’s preprocessing? The author suspected.
Now let’s look at all the code together and compare:
Code that works correctly
#ifdef _WIN32
# define tmpfile w32_tmpfile
#endif
FILE * w32_tmpfile ( void ) {
// code for Windows;
}
else if (code == 200) { // Downloading whole file
/* Write new file (plus allow reading once we finish) */
// FIXME Win32 native version fails here because
// Microsoft's version of tmpfile() creates the file in C:\
//g = fname ? fopen(fname, "w+") : tmpfile();
if(NULL != fname) {
g = fopen(fname, "w+");
} else {
g = tmpfile();
}
}
Code that does not work correctly
#ifdef _WIN32
# define tmpfile w32_tmpfile
#endif
FILE * w32_tmpfile ( void ) {
// code for Windows;
}
else if (code == 200) { // Downloading whole file
/* Write new file (plus allow reading once we finish) */
// FIXME Win32 native version fails here because
// Microsoft's version of tmpfile() creates the file in C:\
g = fname ? fopen(fname, "w+") : tmpfile();
}
Maybe you saw this bug from the beginning, but the author did not. All the problems stem from the comment:
/* Write new file (plus allow reading once we finish) */
// FIXME Win32 native version fails here because
// Microsoft's version of tmpfile() creates the file in C:\
Did you see that last C:\? In C, “\” indicates that the line does not end, so the following code also becomes a comment. This is the real reason for this bug!
The reason why changing to if-else works is that the author commented out the old ternary operator code, so the working code became:
/* Write new file (plus allow reading once we finish) */
// FIXME Win32 native version fails here because Microsoft's version of tmpfile() creates the file in C: //g = fname ? fopen(fname, "w+") : tmpfile();
if(NULL != fname) {
g = fopen(fname, "w+");
} else {
g = tmpfile();
}
I believe that when the author found the cause of this problem, he must have cursed, “Damn it!” I also believe that this bug cost the author a lot of time!
Finally, I will share a mistake I made before.
I had a small function that needed to pass an int* pInt type, and then I needed to use this int* pInt as a divisor in my code. So my code became like this:
float result = num/*pInt; ….
/* some comments */
-x<10 ? f(result):f(-result);
Because I was using vi to write the code at the time, there was no syntax highlighting, and my program compiled successfully, but some strange things happened.
I didn’t know, but when debugging with gdb, I found that some statements just passed.
This problem took me a lot of time, and I finally discovered that the issue was caused by the lack of space, TNND. Below, I will use a code highlighting plugin to show the above code:
float result = num/*pInt;
....
/* some comments */
-x<10 ? f(result):f(-result);
Holy Shit! My code became:
float result = num-x<10 ? f(result):f(-result);
Damn it! My mistake is on par with the author’s mistake in terms of stupidity.
- EOF -
Add the WeChat of the author, not only will your C/C++ skills improve +1
The author will also share C/C++ development learning resources and selected technical articles on personal WeChat, and will occasionally share interesting activities, job referrals, and how to work on side projects with technology.
Add WeChat to open a window.
Recommended Reading Click the title to jump
1. How does C++ perform in embedded systems?
2. C language advanced: Detailed explanation of callback functions
3. One sword breaks all laws: noexcept and C++ exceptions leading to coredump
Follow "CPP Developers"
Read selected C/C++ technical articles
Liking and viewing is the biggest support ❤️