Bug++ of the Month
Ron Burk
Templates are the crucial ingredient for a new style of C++ coding: generic programming. For many programmers, the dream of C++ is one of creating reusable code, but it has been a largely unrealized dream. People who tried to write the only string class youll ever need, for example, were quickly confronted with the reality that different customers of a class have different needs. (I need it fast; you may need it small; etc.)
The dream of achieving high degrees of code reuse in C++ is far from dead, however, having been re-energized by the STL (Standard Template Library). The STL was an impressive demonstration of a programming style that lets you use templates to solve a class of problems and write reusable code that can adapt to the different needs of different customers. It was an impressive enough development that the Standards committee decided to make it part of the C++ Standard late in the game when they were trying (with limited success) to limit new additions.
The STL seems very interesting to me, but I dont use it. Ive heard expert C++ programmers say that template implementations are now mature enough that theres no excuse any more for not using them. I dont know if theyre living on a different planet from me, or if they simply dont use the same compilers as me. What I do know, from observing the stream of bug submissions to this column, is that if I declared that we would henceforth only accept template-related compiler bugs, we would still have plenty of submissions. Until recently, Ive actively avoided using template bugs in this column, but I think its time to start taking them on. Templates are an important part of C++, their definition has now been specified for years, and its time to start expecting compiler vendors to get their implementations debugged.
This Months Bug
This months feature is one of those relatively rare Visual C++ bugs that Microsoft has actually decided to reveal to customers via their website. I wanted to feature it anyway, because I think its representative of the current state of templates, at least as far as most Windows programmers are concerned, since they by and large are Visual C++ users.
Reader (and dedicated bug submitter) John OHalloran provided bug.cpp (Listing 1), which shows the problem code. Its obviously boiled down to the point of absurdity, but you can guess how this arose in real-life code. There are two distinct classes that each have a static function named Fn(). There is a template function that can operate on any class that has a static function named Fn(). This is an essential part of generic programming being able to write code that will operate correctly on any class that satisfies a fairly minimal set of requirements.
The code here is completely legal, and Visual C++ compiles it. The only problem is that the generated code is completely incorrect. The output is:
B static B static
All invocations of the template function operate on class B, no matter what class was actually specified in the template function invocation.
This is a pretty good example of why I still havent started making much use of templates in my C++ code. The main reason I would want to use templates is to build libraries of reusable code, but I cant get too excited about building a library that Im going to have to litter with workarounds for bugs in Visual C++. I sincerely hope that Visual C++ 7 (should I live long enough to see it released) will be a lot closer to implementing templates correctly. Until that happens, or until my code doesnt have to support Visual C++, templates will remain a back burner feature for me.
Microsofts Response
Kerry Loynd of Microsoft provided this response for us:
This is a known bug in all versions of Visual C++. See
support.microsoft.com/support/kb/articles/Q240/8/71.ASP
This bug will be fixed in Visual C++ 7.0.
The URL he mentions goes on to say:
The bug is the result of the way the compiler decorates template function names. Name Decoration uses the arguments and return type and doesnt use the explicitly specified template argument type. Therefore, all [...] template function instantiations receive the same decorated name [...].
Its pretty rare that Microsoft will actually commit to a bug being fixed in a specific release, so Im guessing they know this is a really unacceptable bug and actually have it fixed already in-house. Will the many other Visual C++ template bugs be fixed in the next release? Ill hope for the best.
Summary
How about you? Have you tried to use templates to create reusable code in your own Windows programming? How important or unimportant is template support in Visual C++ 7 going to be to you? Share your template thoughts with me and other readers by sending a note to [email protected]. Or, if youve got a stack of template bugs youve been saving for the day we started covering them, nows your chance. Just boil it down to the smallest possible example, explain whats going wrong (remember, Im not a template expert), and fire it off to [email protected].
Visual C++ 7 could ship tomorrow, or it could ship five years from now. Im betting on sooner, and Im really tired of VC++ 6 bugs, so Ill offer the following bounty to the first person to send us a bona fide new VC++ 7 bug. To make the challenge less trivial, the bug has to be a bug that did not exist in VC++ 6 and (as usual) has to be a language bug in the compiler itself (compiles but shouldnt, should compile but doesnt, crashes the compiler, or generates bad code). In addition to the usual WDJ T-shirt, the winner will also get a years extension added to their WDJ subscription and a free copy of the WDJ CD-ROM of back issues.
Reader Feedback
From: [email protected]
Subject: Apparant goto bug in Visual C++ 6.0
I did not discover this bug myself. A member of the [email protected] (Kevin Palmer) posted it. A lively discussion ensued; the general consensus of which was, It sure looks like a bug, walks like a bug, and quacks like a bug, but the compiler has no bugs, and if they did, the Microsoft people are so smart we would never find it, so it must not be a bug. Since Im not convinced that any significant code, much less Visual Studio, is bug free, and I doubt that the people at Microsoft are somehow inherently smarter than me, I believe this is a bug. It also reportedly does not occur in Visual C++ 4.0. I couldnt find it documented on Microsofts website.
The issue arises if a function has a conditional control path, using a goto, which does not have a valid return statement for all paths. Admittedly, using a goto in this manner is probably a poor design decision, but it would be nice if the compiler handled it correctly. The example that Kevin (the original poster on msvc) gave was this:
int func(void) { int a = 0; bool error = false; if(error) goto Quit; if(a==2) return 3; Quit: a=a; // forgot to return nnnn }
As you can see, the function falls through this code to a=a. The program hangs when func() is called. A quick step through in the debugger and it becomes apparent that it loops back, infinitely, to the quit label. No warning or error is generated. (Well, in warning level 4, the compiler notes that the line containing return 3 is unreachable code.)
I shoved a breakpoint in the program and looked at the disassembly: sure enough, the compiler generates an unconditional jmp after the assignment. The disassembly window looks like this:
17: 18: Quit: 19: a=a; 0040105E mov ecx,dword ptr [ebp-4] 00401061 mov dword ptr [ebp-4],ecx 20: // forgot to return nnnn 21: } 00401064 jmp Quit (0040105e) 00401066 pop edi 00401067 pop esi 00401068 pop ebx 00401069 mov esp,ebp 0040106B pop ebp 0040106C ret
Note the jmp Quit at the top of the function clean-up code.
Continuing the exploration, I found that renaming the file .c (to invoke the C compiler) generates what I would expect from C code the function falls through and returns zero. Also, for kicks, I added a return 9 after the a=a assignment, and while the function exited correctly, the jmp was still present. (The return jumped around it.)
I telnetted into my Linux box at home and tried the code there. egcs let the function fall through, returning garbage. Curiously, egcs did not report an error or warning, by default, although with the -Wall option (to enable all warnings), it correctly noted that not all control paths returned a value.
Now, since I havent used a goto since giving up Applesoft in favor of Turbo Pascal 1.0 on a Z80 running CP/M, Im not completely certain what the rules regarding gotos are in C++. My main reference notes that its an error to have a label immediately before a brace, and that its an error to use goto to jump over declarations (because constructors wont get called), but neither of those situations exists in this case. To whit: it looks like a bug, walks like a bug, and quacks like a bug.
I was almost sold on this one, but fortunately you included an assembly language dump. That started some synapses firing, tickling some dim memories of the past, and, after interminable searching, I discovered that I believe your bug is identical to the bug we reported back in June 1999. I cant fault you for not knowing that, because I could barely remember myself. As the years between Visual C++ upgrades continue to pile up, it gets harder and harder to remember all the bugs featured here that will be fixed in a future release.
Ron Burk is the editor of Windows Developers Journal. You can reach him at [email protected]. Send compiler bug candidates to [email protected].