Saturday, May 11, 2013

Diabolical Defects: The Unfinished Thought

[Editor's Note: Originally published on THE SHORTED TURN's WordPress.com site on 2009/10/10]

Copyright © 2009, 2012 Gary R. Van Sickle

I ran across this one the other day (paraphrased to protect the innocent):

int some_function(void)
{
    int local_var_1 =
    // Ok, set up some file scope variable.
    f_file_scope_var = 4;

    // ...the rest of the function....

    return local_var_1;
}

Note the lack of a semicolon on the local_var_1 line.  The author had started adding this local variable, then got distracted and forgot to complete what he’d already partially added.

“Pfhht, what’s so diabolical about that?”, you ask?  ”Surely, the compiler will choke on that, you’ll easily find and fix it, problem solved!”, you posit?  I must apologize, Gentle Reader, for I have hitherto left out the best part: This did not break the build, nor cause the compiler to issue so much as a warning, nor was it picked up by two different static analysis tools.

Yeah.


So what the heck is going on here?  Well, in a word, nothing: Per the standards, this is 100% legal C and C++ code.  Shouldn’t be, but unfortunately it is.  This is the crux of the issue.  C and C++ specifically allow you to chain assignments (i.e. “x = y = z =123;”), even in initializers (i.e. the “int local_var_1 =” line above).  The assignment expression involving f_file_scope_var results in an lvalue, which is then fair game for use in the initializer expression.  All nice and legal-like.

Now, maybe that’s good and maybe it ain’t, but I have yet to see a single instance of this language feature used to positive effect.  In fact, I rarely see anyone do “x = y = z = …” at all.  There’s a reason for that: you hardly ever need to assign a bunch of variables the same value, and it does nothing but obscure your code.

Now, in this particular instance, the code caught a break: while obviously a fault, due to the logic in the rest of the function, there could not have been a subsequent error and hence no failure.  No harm, no foul, as the kids say these days.  But clearly this sort of thing could easily result in a hard-to-find bug.

“I’m convinced, Shorted Turn!”, you exclaim, “But what can us work-a-day Joe Codejockeys and Jane Bitslingers possibly do to avoid and even prevent this scourge?!?”  Plenty:
  1. Never use the “x = y = z = a = b = c = 5;” idiom.  Ever.
    Now, this would not directly have prevented the Diabolical Defect at hand, but it paves the way for the next item in the list, which would.  Plus, you’re almost certainly not using it anyway, so it’s easy.  If you have a way of enforcing this rule via coding standards or a static analysis tool which can be configured to flag such constructs, do so.
  2. Phone your congressman (or whoever it is who decide these things) and tell him to get Big Language to fix the languages so that initializers like this are not legal C or C++: “int var1 = var2 = var3 = …..;”
    There is no reason for this to be legal C or C++.  Oh sure, Big Language will cry crocodile tears, exclaiming “Oh no!  Think of the TENS of lines of EXISTING CODE that would be TRIVIALLY BROKEN if we corrected the language!!!!”  Sorry Big Language, that dog won’t hunt no more – The Shorted Turn just called your bluff!
Never work, you say?  Ponder the words of Goethe:
“To know is not enough — we must apply; to will is not enough — we must do.” – Johann Wolfgang von Goethe
I say, “Do.”

Until next time Gentle Reader, I remain,

Gary R. Van Sickle
President and CEO/Editor/Head Writer
The Shorted Turn

No comments:

Post a Comment