I believe that such a bug can be made by even the most skilled programmers. Come and see the bug that the author made.
First, the author wanted to use a piece of code to create a file. If a filename is provided, it creates a real file; if not, it calls tmpfile() to create a temporary file.
This piece of code is a C program for HTTP downloading. 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 can cause significant issues for users without administrative privileges. Even on Windows 7, there can be problems even if you have administrative rights.
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 would look 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 hell! 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 had 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();
}
Perhaps 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 subsequent code also becomes a comment. This is the real cause of this bug!!
The reason why changing to if-else worked 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 issue, he must have cursed, “Damn it!” I also believe that this bug cost the author a lot of time!
Finally, I will also share a mistake I made in the past.
I had a small function that needed to take an int* pInt type, and then I needed to use this int* pInt as a divisor in my code. So my code became:
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 strange things happened.
I didn’t know, and when debugging with gdb, I found that some statements just passed.
This issue cost me a lot of time, and I eventually discovered that the problem was caused by the lack of a space. Damn it! 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! My mistake is on par with the stupidity of the bug made by the author above.