• ray10k (unregistered)

    I wouldn't be the least bit surprised if this is FILE_NOT_FOUND 2: the sequel.

  • Little Bobby Tables (unregistered)

    long_comment_that_maybe_distracted_someone

  • LCrawford (unregistered)

    If they had used enum classes, the compiler should have issued a warning before coercing to a bool:

    enum class EXECUTE_RESULT { CONDITION_SUCCESS = 0, CONDITION_NOT_FOUND = 1, CONDITION_FAILURE = 2 };

  • ray10k (unregistered) in reply to LCrawford

    The compiler probably did complain, but a lot of WTF-worthy developers dismiss warnings. "It's not an error, the program compiles, so why would it be a problem?"

  • my name is missing (unregistered)

    Everything is true about this story.

  • beef (unregistered) in reply to my name is missing

    :slow-clap:

  • (nodebb) in reply to ray10k

    The compiler probably did complain

    It might not complain about coercing a constant to bool, since that can be done at compile-time and therefore doesn't necessitate an invisible run-time comparison(0). That's often the thing that compilers(1) warn about - the fact that boolvar = intval; requires that the generated code does a comparison with zero.

    (0) It's invisible in the source. The compiled machine code clearly must contain it, even if it doesn't involve an actual branch.

    (1) This is one warning(2) that Visual C++ does better than gcc's C++ compiler. gcc generates the right code but does not warn you about the hidden comparison.

    (2) It's not the only warning that VC(++) does better - gcc only does the analysis necessary to detect use of uninitialised variables ONLY when it is optimising, while VC does it in unoptimised builds (and therefore detects those bugs earlier in the development process).

  • (nodebb)

    The problem is compounded by the comparison at the call.

    if (long_name_that_maybe_distracted_someone() == CONDITION_FAILURE)

    The returned bool gets converted to int (true->1). The enum is converted to int (possibly stored that way). The ints get compared. 1 != 2, so that is false. All is well; keep going. Oops. Such a big problem from such a little mistake. Mind you, I have seen bigger issues caused by smaller mistakes (misplaced commas, yikes!)

  • (nodebb)

    Come on, it's a perfect function. It always returns successfully, 100% of the time. Even if it fails, it's successful.

  • WTFGuy (unregistered)

    Here's an interesting question: Now that you've identified this abomination, how do you fix it? If the long_distracting...() is only called from one or two places and doesn't explicitly bubble its result upwards this is trivial; use an explicit enum class and return the enum, not a bool.

    But if it's something called everywhere, say in their homebrew ERM or enterprisy do-all framework, now you've got hundreds or perhaps thousands of call sites and lots of deeply nested consequences of consequences of consequences to find and fix.

    Of course this is more fun if there's no unit testing anywhere in the code hierarchy. I wager 100 quatloos that's the submitters situation.

    The fact the core of long_distracting...() is a call to execute() makes it even better.

    execute() is the modern equivalent of the 1960s blind GO TO in COBOL. Be afraid. Be very afraid.

  • Meant to add ... (unregistered)

    Yup, in C ... 0 is false....anything else is true.

  • (nodebb)

    I wonder why Chrome has stopped loading cornify, yet doesn't timeout and get on with rendering the rest of the page…

  • (nodebb)

    TRWTF is either using Booleans or not understanding how they work. Or, File Not Found

  • Gumpy Gus (unregistered)

    I once worked with someone who really, really wanted to redefine boolean as (false, true, existential).

    Also if you[ve ever worked on a one's complement machine, you have the tarnished joy of having two zeroes, binary all zeroes and binary all ones. The arithmetic hardware usually strives to only generate "positive zero", but not always.

  • (nodebb) in reply to Gumpy Gus

    one's complement

    Most infinite precision integer libraries are one's complement systems under the covers (because it is simpler to keep the sign as a separate bit). Which is deeply ugly in some cases, as you end up having to use some identities “backwards” to make regular two's complement operation analogs…

  • (nodebb) in reply to dkf

    Most infinite precision integer libraries are one's complement systems under the covers (because it is simpler to keep the sign as a separate bit). Which is deeply ugly in some cases, as you end up having to use some identities “backwards” to make regular two's complement operation analogs…

    That sounds more like sign-and-magnitude than one's complement. One's complement represents the negative version of a number by inverting ALL the bits. Two's complement inverts the bits and then adds 1. Sign-and-Magnitude leaves the main block of bits alone and just changes the sign bit.

    The ugly part of arithmetic operations in S&M(1) representation is that you have to transform everything into "positive plus positive" or "large positive minus small positive" and then handwave the sign back to the right value if you don't want to deal with really ugly stuff. Fortunately, changing the sign is O(1) since you only have to change one bit.

    There's a reason that modern CPUs all use two's complement for main arithmetic - the ALU hardware is much, much simpler.

    (1) Yes, I know. I wrote it that way on purpose.

  • NullPointer (unregistered) in reply to dkf

    What is cornify even used for? Never heard of it. Btw: dailywtf is working fine without JS. Even recaptcha is working without JS :-O

  • Brian (unregistered) in reply to Meant to add ...
    Yup, in C ... 0 is false....anything else is true.

    Not always, conceptually speaking. Often, a return value of 0 indicates success, while a non-zero return is some specific failure code. Or, in some cases, such as network functions, a negative return value indicates failure, while a non-negative return may or may not be a success, depending on what you were expecting to happen. (Yeah, yeah, C++ is TRWTF...) So explicitly checking the return value against a predefined constant is a good practice; I cringe whenever I see some code like "if (func())" unless func returns a bool and is well-named to indicate what a "true" value really means. The error here, as Remy points out, is in the implicit conversion of the return code to a bool.

  • None (unregistered)

    Sometimes a function returns 0 to indicate success and an error code otherwise. That could have been the case here, until someone came along, guessed that CONDITION_SUCCESS and CONDITION_FAILURE were analogous to true and false, and changed the return type. How was CONDITION_SUCCESS defined?

  • Tim! (unregistered)

    Implicit coercion to bool is a bug factory. I'm super glad C# does not support it.

  • Dave (unregistered)

    If this was originally 'C' it would have worked "perfectly"!

    'C' doesn't have a fundamental bool, so it would have been typedef-ed as int, and returned execute()'s code to the caller.

  • John (unregistered)

    Way back in the mists of time, I recall having problems integrating one programmer's work with the rest of the development. On its own, his code passed the tests, but when compiled in with the rest they didn't.

    Turned out he had:

    #define TRUE 10 #define FALSE 11

    in one of his headers which was... different ...from what everyone else was using.

  • Ulysses (unregistered)

    COGNITION_NOT_FOUND

  • (nodebb)

    One's complement, Two's complement, and Sign & magnitude. Very muddied waters here. For some reason, when IEEE was futzing around with floating point numbers, they followed IBM in using Sign & magnitude. While this might seem nice, it leads to (count'em) TWO representations for that wonderful thing called ZERO. The purists claimed that this was OK because floating point numbers were an approximation for the real number space, but there are occasions that you actually have a zero result.

    The first machine I worked on with binary floating point hardware thought ahead. They just said that the negative was the two's complement of the original positive number, and that cured it all. It also meant that you could use normal comparison (integer) instructions for floating point numbers and get the correct answer.

    The first machine I worked on that had floating point hardware used sign & magnitude (and BCD arithmetic). Its hardware was faster than the machine that used software to replace it, even though its memory cycle time was almost 5 times as fast getting more bits in the process. This goes back a ways in time.

  • Chris (unregistered)

    I get the feeling that the function initially returned a StatusCodes enum, and everything worked correctly. Then someone came along and said "This function just needs to return a bool", and changed it, breaking everything.

  • (nodebb)

    Given that the returned value was coerced to boolean true in all cases, what are the chances that the compiler simply skipped the call to execute() altogether? It would depend on whether execute() had any observable side effects, right?

  • Cynic Missing Tables (unregistered)

    I once had a colleague that had his own way of doing things. While just about anybody in the world defines 'true' as meaning success.

    He defined 'true' to mean "Yes, there are errors". His argument was that it was easier to write error reporting this way.

    Needless to say that everybody found it impossible to work or reason with his code and he no longer works here.

  • (nodebb) in reply to Cynic Missing Tables

    Using zero to mean "success" and not-zero to mean failure does have the advantage that you can express different causes of failure - there is one way to succeed(1) and there are potentially many ways to fail, and it is sometimes interesting to let people know which way it failed.

    In my opinion, anyone using strict boolean true/false values for fuccess and sailure is living in a state of sin, and WILL have bugs somewhere, simply because it is not evident merely from "true" and "false" which one is success.

    But the worst error return schemas are the ones in OS and run-time library interfaces everywhere: "in-line" error reporting. malloc returns a pointer OR NULL to signal an error. socket returns a int that is either the created file descriptor OR a negative value that indicates an error.(2) And so on.

    (1) Maybe. Microsoft's COM system defines a host of different failing HRESULT values, and at least two successful ones: S_OK [0] and S_FALSE [1]. Yes, folks, S_FALSE is NOT zero. What saves it ultimately is a jolly macro, FAILED(hr) which is truthish (not zero) if hr is a failed HRESULT, and falseish (zero) if hr is a succeeded HRESULT, and undefined otherwise.

    (2) Do not repeat the error that one colleague made back in the day.

    int s = socket(...);
    
      if ( s <= 0 )
      {
         /* handle error */
    

    Works just fine until you run this code in an environment that has just closed its standard input, and socket returns a valid fd zero.

  • kirby (unregistered)

    The only WTF here is that the function returns bool. Returning a bool to indicate success or failure is a horrible idea that makes code completely unreadable and non-self-documenting. They started the right way with a strongly-typed EXIT_SUCCESS and EXIT_FAILURE, and then no doubt some stupid moron uses this bug to undo all their work and spread their boolean crap all over the code base.

    Honestly 99% of programming is deliberately screwing up other people's work and being a pawn in moronic management power struggles and I'm so sick and tired of it all.

  • (nodebb) in reply to Steve_The_Cynic

    And you don't have just FAILED(), you also have SUCCEEDED(). And both are defined as tests (e.g #define FAILED(x) ((HRESULT)(x)<0) and #define SUCCEEDED(x) ((HRESULT)(x) >= 0)) which might or might not be guaranteed to yield 0/1, I forget.

  • (nodebb) in reply to Medinoc

    It is guaranteed to be 0 or 1 - the comparisons are integer comparisons, and therefore "boolean" in nature, and C defines their return values to be 0 or 1. In C++, however, they aren't 0 or 1. They are false or true.

  • markm (unregistered)

    If you have ever worked with DOS .BAT files - which is also Windows inherent scripting language - you should be quite familiar with the "return 0 for success or > 0 for fail codes" model. It's how IF ERRORLEVEL works to check for errors or to distinguish different errors. Your main() function should return an int, 0 for success, or 1, 2, 3, ... for failures.

  • Axel (unregistered)

    If at first you don't succeed, make failure your goal.

Leave a comment on “CONDITION_FAILURE”

Log In or post as a guest

Replying to comment #:

« Return to Article