| « Hey Kids, Don't Smoke in the Rain | Scheming Schema » |
It was a dark and stormy night. The kind of night envisioned by Mr. Bulwer-Lytton when he penned his infamously bad opening sentence, but the weather was not a deterrent to Craig. Craig faced a task more daunting than mere lightning and rain. He was on the trail of an annoying bug and was determined to track it down come hell or high water (a possibility made more real given the weather).
How Craig came to this point is not unfamiliar to anyone who writes code. It was the last day of the sprint, in fact, it was more like the last hours of the sprint. He had been struggling mightily against the whims of programming fortune all day (and into the evening) trying to stamp out the final stubborn bugs in a feature that was his responsibility. A feature that, if it wasn’t delivered, would mean a failed sprint for the entire team.
Down to one last issue, all he needed to do was to figure out the inner workings of the following line of code.
nonRunnerForm.MidPrice = ((Convert.ToDecimal(row.Item(HermesColumns.Events.LiveBuyPrice)) + _ Convert.ToDecimal(row.Item(HermesColumns.Events.LiveSellPrice)) ) / 2D)
In and of itself, this is not an egregious example of bad code. In fact, it looks like code found in a wide variety of production grade applications. And yet when the line was executed, the value of nonRunnerForm.MidPrice was 0.
Always.
Regardless of what values were found in the row.Item array.
Craig found numerous ways to beat his head against this particular wall. He checked the types of the variables involved. He checked for the possibility of integer division. He rechecked the variable types. Still the storm continued to rage both outside and inside his office.
Then, in a flash of insight, lightning struck. Metaphorically, that is.
With thunder still rumbling through his office, Craig stepped into the nonRunnerForm.MidPrice property and this is what he found:
Public Property MidPrice() As Decimal
Get
Return mMidPrice
End Get
Set(ByVal value As Decimal)
ctlNonRunnerPad.MidPrice = value
End Set
End Property
Problem solved. Feature delivered. The team celebrated a successful sprint. And Craig has become a vocal advocate for writing unit tests, even for properties.
|
I've seen worse recently. Code that worked for someone else but which crashed on my machine with a bus error (i.e., a dereference of a NULL pointer). The NULL value apparently came from a function that would specifically make the process panic nicely if the memory allocation failed; it had a (properly checked) guarantee that it never returned NULL. In short, an impossible error was happening after a function call that was guaranteed to never silently fail; even staring very hard at the memory allocator was no help at all.
The actual problem? There was a system call (to stat()) between the memory allocation point and the place where the allocated buffer was used. Due to a reordering of #include directives in a separate file (it's never close by) there was a fundamental disagreement over whether it was really stat() or stat64() that was actually being used, with the result was that the stack variable holding the buffer for the system call was too small and the OS was scribbling a NULL over the next word on the stack, which happened to be the address of the other allocated memory block. Boom! (Oh, and the mixup only happened on some versions of one particular platform. Other platforms and other versions didn't have the problem in the first place.) Sometimes you've really got to follow Sherlock Holmes's dictum when bug hunting: when you have eliminated the impossible, whatever remains, however improbable, must be the truth. |
| « Hey Kids, Don't Smoke in the Rain | Scheming Schema » |