Defensive Programming and a Whole Lot More

« Return to Article
  • Code Dependent 2009-05-15 09:01
    if (!comment) return fist;
  • Scott 2009-05-15 09:05
    global_NewAceUser_Yes=No
    global_NewAceUser_No=Yes

    That's called default deny. It's mandatory in all security software for Sarbanes Oxley compliance.
  • Jerry 2009-05-15 09:07
    Josh's predecessor seemed to miss out on the fundamentals the request/response paradigm.

    ... while Josh, in turn, missed out on the fundamentals the English grammar.
  • kastein 2009-05-15 09:13
    I bet whoever wrote the "do I exist" C++ class defense noticed that that was checked after "new <whateverclass>" every time, so he figured hey, I can put this code in one place and stop duplicating it! Either that, or it's from some abomination of a mixed-language application and the class is used through some strange wrapper from another language and might not be trusted to actually set the "this" pointer while calling. Either way, WTF?
  • Blob 2009-05-15 09:25
    Jerry:
    Josh's predecessor seemed to miss out on the fundamentals the request/response paradigm.

    ... while Josh, in turn, missed out on the fundamentals the English grammar.


    "of" has been deprecated
  • Code Dependent 2009-05-15 09:25
    // Function to confirm before deletion
    function Custom_Confirm(message)
    {
    // Show confirmation message
    var confirmation = confirm(message);

    // If confirmed then return false to stop form submit
    if (!confirmation)
    {
    return false;
    }
    else
    {
    return true;
    }
    }
    Boy, that's a case of taking the taxi across town to get to your next door neighbor's house.

    The logic here all hinges on what is returned for what state by confirm(message). The comment says "If confirmed then return false", but then they return false for ! confirmation. I imagine the comment was supposed to say:
    // If not confirmed then return false to stop form submit

    So instead of:
    var confirmed = Custom_Confirm(messageToConfirm);

    ...how about this?
    var confirmed = confirm(messageToConfirm);
  • Code Dependent 2009-05-15 09:28
    Blob:
    Jerry:
    Josh's predecessor seemed to miss out on the fundamentals the request/response paradigm.
    ... while Josh, in turn, missed out on the fundamentals the English grammar.
    "of" has been deprecated
    Yes, "the" is now used in its place.
  • Tom C 2009-05-15 09:31
    if (!this) return false;

    Gives the optimizer something to work with, making the runtime more efficient.

    (And is it just me, or has this site become a lot more boring since TopCod3r went silent?)
  • Gnubeutel 2009-05-15 09:32

    Boolean answer = new Boolean(
    inp.equals("true")
    ? new Boolean(true)
    : new Boolean(false)).booleanValue();


    That is wrong on so many levels. It should be used as an example in programming classes.
    I count at least three redundant/useless operations and another three things you shouldn't do because there are more efficient ways. And i'm probably missing some more.
    I just hope there were a lot of blind mass refactorings involved in the creation of this statement.
  • Médinoc 2009-05-15 09:34
    kastein:
    I bet whoever wrote the "do I exist" C++ class defense noticed that that was checked after "new <whateverclass>" every time, so he figured hey, I can put this code in one place and stop duplicating it! Either that, or it's from some abomination of a mixed-language application and the class is used through some strange wrapper from another language and might not be trusted to actually set the "this" pointer while calling. Either way, WTF?

    Unlike Java, it's possible in C++ to call a class member function from a null pointer. If the function is not virtual, the program will not crash before entering it, and it won't crash inside the function either if no member variables are accessed.

    An Example from a well-known UI class library:
    HWND CWnd::GetSafeHwnd()
    
    { return this ? m_hWnd : null; }
  • Jamie 2009-05-15 09:34
    Blob:
    Jerry:
    Josh's predecessor seemed to miss out on the fundamentals the request/response paradigm.

    ... while Josh, in turn, missed out on the fundamentals the English grammar.


    "of" has been depreciated


    FTFY
  • Henning Makholm 2009-05-15 09:36
    I'm not convinced that "if(!this)" is a WTF. For a nonvirtual function, most compilers would probably be happy to produce code that called the function through a null pointer. (This is probably undefined behavior at runtime, but by far the most common *actual* behavior must be to attempt to execute the function body with this being null).

    On the other hand, silently returning false as a defensive action is a lot more questionable. That just exchanges a segfault-and-core-dump here and now with wrong results further down the road that could be a lot harder to debug.

    Perhaps the product of faulty metrics, such as "the programmer in whose code the segfault occurred is to be blamed for the bug"?
  • jspenguin 2009-05-15 09:36
    The C++ one is obviously some kind of attempt to defend against dereferencing NULL pointers. It fails miserably under the following conditions:

    1. Member access
    2. Virtual methods
    3. Multiple inheritance, when the method is in a base class that is *not* the first class:


    class A {
    public:
    int a;
    virtual ~A() { }
    };

    class B {
    public:
    int b;
    virtual ~B() { }
    bool nullprotect() {
    if (!this) return false;
    return (b != 0);
    }
    };

    class C : public A, public B {
    public:
    int c;
    };

    int main() {
    B* pb = NULL;
    C* pc = NULL;

    cout << "pb: " << pb->nullprotect() << endl; // prints "pb: false"
    cout << "pc: " << pc->nullprotect() << endl; // segfault!

    }



    The reason is that in order to get a pointer to B from a pointer to C, you have to add a constant offset (8 bytes on a 32-bit system), so when pc->nullprotect() is called, this is (B*)0x8.

    If nullprotect were virtual, the compiler would actually generate a tiny "thunk" function that adds a constant value to this and jumps to the original function.

  • AC 2009-05-15 09:38
    It's like running across those branches that begin with a comment saying "this should never happen"

  • amischiefr 2009-05-15 09:40
    global_NewAceUser_Yes=No
    global_NewAceUser_No=Yes

    This was obviously written by a woman. When they say yes it means no and when they say no it means yes. At least that's what I told the judge.
  • Tom C 2009-05-15 09:46
    amischiefr:
    global_NewAceUser_Yes=No
    global_NewAceUser_No=Yes

    This was obviously written by a woman. When they say yes it means no and when they say no it means yes. At least that's what I told the judge.

    I hope, for your sake, the "jury of your peers" was all male.

    Then again...

    Judge: Guilty?

    Male jurors: No.

    Female jurors: Yes.

    So, you're fine.
  • Buddy 2009-05-15 09:49
    if (!this) return false;

    It's perfectly legitimate because it's entirely possible to cast NULL to an object and use it to call non-virtual functions. Not smart or safe, but you'll see it throughout MS code.

    E.g.

    HDC hdc = ((CDC *)NULL)->GetSafeHdc();

    Yet another gotcha of C++...





  • Leo 2009-05-15 09:55
    The Real WTF is caring whether code works in IE6 or not. Bet it doesn't work in Lynx, SlipKnot, or Netscape 3 either.
  • Vollhorst 2009-05-15 09:55
    Buddy:
    if (!this) return false;

    It's perfectly legitimate ...

    Yet another gotcha of C++...
    Aye, it is a simple solution of null pointer problems. It is no good design but sometimes it really makes sense.

    Some people simply forget that member functions of classes are nothing else then normal class-less functions with a hidden parameter (this).
  • methinks 2009-05-15 10:01

    Boolean answer = new Boolean(
    inp.equals("true")
    ? new Boolean(true)
    : new Boolean(false)).booleanValue();
    "We had a strange problem wherein a procedure wasn't always returning the expected value," writes Jake T, "upon digging through the procedure's code, it was pretty apparent why."
    ALTER FUNCTION [CMM].[FetchItemCode]
    (
    )
    RETURNS bigint
    AS
    BEGIN
    RETURN 29654
    END


    Well, unless of course you expect 29654 as the answer, which the OP doesn't say isn't the case...
  • Stilgar 2009-05-15 10:04
    The real WTF is Java's boxing model!
  • Rootbeer 2009-05-15 10:04
    Leo:
    The Real WTF is caring whether code works in IE6 or not. Bet it doesn't work in Lynx, SlipKnot, or Netscape 3 either.


    IE6 still accounts for 15% of the traffic to the site I operate at my day job. Do you think management would be happy if sales were to drop by 15%?
  • Georgem 2009-05-15 10:08
    Mine's bigger

    Boolean[] values = new Boolean[new Boolean(Boolean.TRUE), new Boolean(Boolean.FALSE)]
  • Tom C 2009-05-15 10:08
    Leo:
    The Real WTF is caring whether code works in IE6 or not. Bet it doesn't work in Lynx, SlipKnot, or Netscape 3 either.

    I attended a two hour information security class last night. When I saw all their computers were running IE6.0, I concluded I wasn't going to be learning anything useful from them. And this indeed turned out to be the case.

    More peculiar was that when I pointed it out to the others in the class -- all alleged security pros -- the most common response was "what version should it be?"
  • pete 2009-05-15 10:11
    Rootbeer:
    IE6 still accounts for 15% of the traffic to the site I operate at my day job. Do you think management would be happy if sales were to drop by 15%?

    They seem to be happy -- obsessed even -- with eliminating the sales from Firefox users, Mac users, etc...
  • Tim Smith 2009-05-15 10:22
    I wouldn't depend on the (!this) stuff since the standard specifically states that the behavior is undefined. You can invoke a static function from a null pointer, but that is it.
  • Anonymous 2009-05-15 10:28
    Leo:
    The Real WTF is caring whether code works in IE6 or not. Bet it doesn't work in Lynx, SlipKnot, or Netscape 3 either.
    Simply compare the market share of IE6, Lynx, SlipKnot and Netscape 3 - then you will see exactly why people still care about IE6.

    I would say "bad troll" but we all bit, so maybe it wasn't such a bad troll after all.
  • Charles400 2009-05-15 10:55
    "I was going over some code from a SDK released by you know who," Tammie Kong wrote. "There were a few questionable things in it, but then I found a single line that made me pause. I realize string.format() has its advantages and all, but this just seemed ridiculous."

    No, I don't know who. Who?
  • Pedant 2009-05-15 10:56
    The real WTF is that someone thinks that "!this" is a WTF in C++. Please do us a favor and stay far away from C++ until you learn what you are doing.

    Bjarne Stroustrup uses "if (this==0)" twice on page 605 of "Programming: Principles and Practice using C++". It isn't needed in every method, but it isn't automatically a WTF.
  • Steve 2009-05-15 10:59
    [quote user="Jamie"]
    [quote user="Blob"]
    [quote user="Jerry"]
    Josh's predecessor seemed to miss out on the fundamentals the request/response paradigm.[/quote]
    ... while Josh, in turn, missed out on the fundamentals the English grammar.[/quote]
    "of" has been depreciated
    [/quote]
    FTFY
    [/quote]
    No, you didn't.
  • Steve 2009-05-15 11:00
    Jamie:
    Blob:
    Jerry:
    Josh's predecessor seemed to miss out on the fundamentals the request/response paradigm.

    ... while Josh, in turn, missed out on the fundamentals the English grammar.

    "of" has been depreciated

    FTFY

    No, you didn't.
  • awfwefewa 2009-05-15 11:10
    ALTER FUNCTION [CMM].[FetchItemCode]
    (
    )
    RETURNS bigint
    AS
    BEGIN
    RETURN 29654
    END
    TDD mocking?
  • CAT 2009-05-15 11:22
    Leo:
    The Real WTF is caring whether code works in IE6 or not. Bet it doesn't work in Lynx, SlipKnot, or Netscape 3 either.


    The Real WTF are sites which rely on JS (or Flash, Java, ...) for basic functionality.
  • anon 2009-05-15 11:27
    AC:
    It's like running across those branches that begin with a comment saying "this should never happen"

    As long as this case is properly handled, there's nothing wrong with it. Think of external input that will be between -10 and 10. If it leaves those bounds (power surge, earthquake, sensor failure etc.) than there is no correct response from the program, which may therefore (gracefully) shut down.

    Now, if you didn't have that branch, the program would still happily continue with wrong values.
  • Jamie 2009-05-15 11:41
    Steve:
    Jamie:
    Blob:
    Jerry:
    Josh's predecessor seemed to miss out on the fundamentals the request/response paradigm.

    ... while Josh, in turn, missed out on the fundamentals the English grammar.

    "of" has been depreciated

    FTFY

    No, you didn't.


    Sorry... I guess you had to be here yesterday....
    I was just running the script provided by "Language Nazi"
  • SCJP 2009-05-15 12:12
    Boolean answer = new Boolean(
    inp.equals("true")
    ? new Boolean(true)
    : new Boolean(false)).booleanValue();
    For those not familiar with Java:
    Boolean answer = new Boolean(inp);
    ...simply does the trick.
  • DaveK 2009-05-15 12:19

    the actual code and it was a even more surprising than I had remembered."

    #define NEGATIVE_ONE 0

    What's surprising about that? When it comes to boolean values, zero is the negative one. And '1' is the positive one. See?

  • Code Dependent 2009-05-15 12:20
    SCJP:
    Boolean answer = new Boolean(
    inp.equals("true")
    ? new Boolean(true)
    : new Boolean(false)).booleanValue();
    For those not familiar with Java:
    Boolean answer = new Boolean(inp);
    ...simply does the trick.
    return new Boolean(
    "Boolean answer = new Boolean(inp);" ...simply does the trick
    ? new Boolean(true)
    : new Boolean(false)).booleanValue();
  • lolwtf 2009-05-15 12:33
    Code Dependent:
    Blob:
    Jerry:
    Josh's predecessor seemed to miss out on the fundamentals the request/response paradigm.
    ... while Josh, in turn, missed out on the fundamentals the English grammar.
    "of" has been deprecated
    Yes, "the" is now used in its place.
    What a load the nonsense. I'd rant about it, but I have to log thef.
  • shadowman 2009-05-15 12:37
    I don't get the String.format() one.
  • Tom 2009-05-15 12:41
    Someone explain to me the javascript one. Is the WTF that the comment and the if (!confirmed) don't match? I'm going crazy trying to see what is wrong with this (maybe just because it is Friday...)
  • Tom 2009-05-15 12:45
    Tom:
    Someone explain to me the javascript one. Is the WTF that the comment and the if (!confirmed) don't match? I'm going crazy trying to see what is wrong with this (maybe just because it is Friday...)


    I mean, other than the fact that there is a lot of unnecessary code (assuming that the comment is incorrect, but the code is right...)

    Sorry for the double-post, can't edit since I am not registered...
  • SCJP 2009-05-15 12:45
    shadowman:
    I don't get the String.format() one.
    Splitting the SQL string into four parts first and let String.Format() put it together afterwards is somehow senseless.
  • wrtlprnft 2009-05-15 12:49
    if(!this) {
    throw new NullPointerException();
    }
  • Code Dependent 2009-05-15 12:50
    Tom:
    Tom:
    Someone explain to me the javascript one. Is the WTF that the comment and the if (!confirmed) don't match? I'm going crazy trying to see what is wrong with this (maybe just because it is Friday...)


    I mean, other than the fact that there is a lot of unnecessary code (assuming that the comment is incorrect, but the code is right...)

    Sorry for the double-post, can't edit since I am not registered...
    The entire method is superfluous. See my comment on that above.
  • shadowman 2009-05-15 12:51
    Tom:
    Someone explain to me the javascript one. Is the WTF that the comment and the if (!confirmed) don't match? I'm going crazy trying to see what is wrong with this (maybe just because it is Friday...)


    The whole function is an unnecessary wrapper around

    var confirmation = confirm(message);

    It doesn't add anything beyond that one line.
  • Code Dependent 2009-05-15 12:52
    SCJP:
    shadowman:
    I don't get the String.format() one.
    Splitting the SQL string into four parts first and let String.Format() put it together afterwards is somehow senseless.
    No kidding. Somebody ought to put it up on a website somewhere that features stuff like that.
  • Rich 2009-05-15 12:52

    We did something similar to this back in our Windows 3.1 programming days. But it was

    assert(this);

    at the top of every method. We were using the Borland compiler.

    The problem was that you could call non virtual methods without a valid "this" pointer (because those methods weren't put into the virtual table) and we would end up with segfaults or other assertions farther down in the code.

    Not all class methods touched the "this" pointer, but we wanted to assert() the failure sooner rather than later.

    Moving the assert(this) higher up in the stack showed the developer immediately that he was dealing with a null pointer. Not that he shouldn't have been asserting his pointer earlier.. but in win16 programming we believed in belts AND suspenders!

    And yes, it doesn't work for virtual functions in subclasses. But virtual functions weren't what we were trying to protect! Ideally you should segfault when the compiler indexes into the bad virtual table pointer. (And then often bring down your Windows 3.1 with it!)

  • Jay 2009-05-15 12:57
    anon:
    AC:
    It's like running across those branches that begin with a comment saying "this should never happen"

    As long as this case is properly handled, there's nothing wrong with it. Think of external input that will be between -10 and 10. If it leaves those bounds (power surge, earthquake, sensor failure etc.) than there is no correct response from the program, which may therefore (gracefully) shut down.

    Now, if you didn't have that branch, the program would still happily continue with wrong values.


    It's like, Why do we waste money hiring police? After all, people SHOULD never break the law.
  • Steven Noonan 2009-05-15 12:59
    The whole
    if (!this) dieHorribly();
    thing actually does make sense. Something like
    assert(this);
    would make more sense, but the rationale for it is fairly simple. Let's say you have some badly written code like this:
    SomeClass *instance = NULL;
    
    instance = getSomeInstance(someParameter);
    instance->badFunctionCall();
    The return value of 'getSomeInstance' isn't checked, so it could return NULL. Instead of segfaulting on the badFunctionCall() it will just hit an assertion failure in the case that you have an assertion on the 'this' pointer, because 'this' would be NULL. It's even' better if you have a custom assertion function that prints debugging info, because you can easily figure out where you made a mistake in your program.
  • OldCoder 2009-05-15 13:01
    SCJP:
    shadowman:
    I don't get the String.format() one.
    Splitting the SQL string into four parts first and let String.Format() put it together afterwards is somehow senseless.

    D'oh! You don't need the SQL at all, since all it selects is two fields which are the same as the values it supplies.
  • Jamie 2009-05-15 13:13
    OldCoder:
    SCJP:
    shadowman:
    I don't get the String.format() one.
    Splitting the SQL string into four parts first and let String.Format() put it together afterwards is somehow senseless.

    D'oh! You don't need the SQL at all, since all it selects is two fields which are the same as the values it supplies.


    You do if you want to find out if it is actually in the database... But that's not the way to do it!
  • SCJP 2009-05-15 13:15
    OldCoder:
    SCJP:
    shadowman:
    I don't get the String.format() one.
    Splitting the SQL string into four parts first and let String.Format() put it together afterwards is somehow senseless.

    D'oh! You don't need the SQL at all, since all it selects is two fields which are the same as the values it supplies.
    Hehe, that's right! Didn't look at the semantics, just at the syntax. Now, that's really ridiculous.
  • Tom 2009-05-15 13:17
    That is what I was thinking. I just wanted to make sure I wasn't missing something else, because I know I'd written similar crap when I first started.
  • Captain Oblivious 2009-05-15 13:25
    Smut
  • kastein 2009-05-15 13:32
    Médinoc:
    kastein:
    I bet whoever wrote the "do I exist" C++ class defense noticed that that was checked after "new <whateverclass>" every time, so he figured hey, I can put this code in one place and stop duplicating it! Either that, or it's from some abomination of a mixed-language application and the class is used through some strange wrapper from another language and might not be trusted to actually set the "this" pointer while calling. Either way, WTF?

    Unlike Java, it's possible in C++ to call a class member function from a null pointer. If the function is not virtual, the program will not crash before entering it, and it won't crash inside the function either if no member variables are accessed.

    An Example from a well-known UI class library:
    HWND CWnd::GetSafeHwnd()
    
    { return this ? m_hWnd : null; }


    Yikes, how the hell did I forget that you could cast a null pointer to the class and call its methods? I've been writing C and assembly for too long...

    (and I don't really know Java)
  • soup 2009-05-15 13:38
    Médinoc:
    kastein:
    I bet whoever wrote the "do I exist" C++ class defense noticed that that was checked after "new <whateverclass>" every time, so he figured hey, I can put this code in one place and stop duplicating it! Either that, or it's from some abomination of a mixed-language application and the class is used through some strange wrapper from another language and might not be trusted to actually set the "this" pointer while calling. Either way, WTF?

    Unlike Java, it's possible in C++ to call a class member function from a null pointer. If the function is not virtual, the program will not crash before entering it, and it won't crash inside the function either if no member variables are accessed.

    An Example from a well-known UI class library:
    HWND CWnd::GetSafeHwnd()
    
    { return this ? m_hWnd : null; }


    "I invented the term Object-Oriented and I can tell you I did not have C++ in mind." -- Alan Kay
  • Weps 2009-05-15 14:02
    Pedant:

    Bjarne Stroustrup uses "if (this==0)" twice on page 605 of "Programming: Principles and Practice using C++". It isn't needed in every method, but it isn't automatically a WTF.


    If he meant "if (this==NULL)" then it's definitly a wtf.
  • tiller 2009-05-15 14:17
    Having assert(this) might make sense(But I would really like my compiler to always do that in debug mode. Having to add the code to all my methods by 'hand is' is stupid).

    but having
    if(!this) return false
    is a wtf because it transform a 'fast fail' into something that return an arbitrary value, thus causing a hell for debugging later.

    Or maybe the code is supposed to 'work correctly' when called on a null pointer, but that would be its own wtf(And would depend on the exact way the compiler would generate code).







  • Anonymous Cowherd 2009-05-15 14:24
    Here's the thing:

    In very very very early C++ days, there were no static methods. So if you wanted to define one, you'd have to do it as a free function -- but if you did, you lost access to any private static members. So instead, the idiom for a static method was to do ((Foo *)(0))->blah(). If you look at sufficiently old books, this is still used in some places.
  • Loren Pechtel 2009-05-15 14:41
    The problem with the !this is not the test, it's what's done about it. On occasion it might make sense to return false if called on a null but that certainly shouldn't be the normal result. The desired result generally should be to die.


    I could believe this started from somebody getting blamed for crashes due to someone else's code and they did this so the blowups wouldn't be in their code and then it somehow became standard practice.
  • anon 2009-05-15 14:52
    Unlike Java, it's possible in C++ to call a class member function from a null pointer. If the function is not virtual, the program will not crash before entering it, and it won't crash inside the function either if no member variables are accessed.

    An Example from a well-known UI class library:

    HWND CWnd::GetSafeHwnd()
    { return this ? m_hWnd : null; }


    That depends on your definition of "possible". The code will compile all right, so by one definition it's "possible". At runtime, however, you've just entered undefined territory, and it may well NOT be "possible" to make that call at run time. Worse, it's legal for that call to now format your hard drive (yeah, I'm being pedantic, as no implementation is going to do this, but the point stands).

    Many implementations allow that call, so it's debatable whether or not checking if "this == 0" is ever something to consider doing. I think most would side on the act being a WTF, though, especially if you do anything other than cause some sort of immediate failure (and returning a value, even an error code, doesn't fit that definition). The GetSafeHwnd() is a WTF, though it was there for a reason. Always doing a "return false" is a WTF, and there can't be a defensible reason.
  • Leak 2009-05-15 15:05
    CAT:
    The Real WTF are sites which rely on JS (or Flash, Java, ...) for basic functionality.

    What, like Google Maps?

    np: Prefuse 73 - Half Up Front (Everything She Touched Turned Ampexian)
  • Pedant 2009-05-15 16:21
    Loren Pechtel:
    The problem with the !this is not the test, it's what's done about it. On occasion it might make sense to return false if called on a null but that certainly shouldn't be the normal result. The desired result generally should be to die.


    Wrong.

    Link* Link::insert(Link* n)
    {
    if (n==0) return this;
    if (this==0) return n;
    ...
    }

    from Bjarne Stroustrup, "Programming: Principles and Practice Using C++", p. 605.
  • Pedant 2009-05-15 16:21
    Weps:
    Pedant:

    Bjarne Stroustrup uses "if (this==0)" twice on page 605 of "Programming: Principles and Practice using C++". It isn't needed in every method, but it isn't automatically a WTF.


    If he meant "if (this==NULL)" then it's definitly a wtf.


    What are you talking about? NULL and 0 are synonymous in C++.
  • paulm 2009-05-15 17:19
    SCJP:
    For those not familiar with Java:
    Boolean answer = new Boolean(inp);
    ...simply does the trick.


    Although,
    Boolean answer = Boolean.valueOf(inp);

    is even better, as it avoids pointlessly creating extra Boolean object instances.

  • Long 2009-05-15 17:40
    shadowman:
    Tom:
    Someone explain to me the javascript one. Is the WTF that the comment and the if (!confirmed) don't match? I'm going crazy trying to see what is wrong with this (maybe just because it is Friday...)


    The whole function is an unnecessary wrapper around

    var confirmation = confirm(message);

    It doesn't add anything beyond that one line.


    What if confirm() returns FILE_NOT_FOUND?
  • Single User 2009-05-15 17:45
    Pedant:
    Loren Pechtel:
    The problem with the !this is not the test, it's what's done about it. On occasion it might make sense to return false if called on a null but that certainly shouldn't be the normal result. The desired result generally should be to die.


    Wrong.

    Link* Link::insert(Link* n)
    {
    if (n==0) return this;
    if (this==0) return n;
    ...
    }

    from Bjarne Stroustrup, "Programming: Principles and Practice Using C++", p. 605.

    ((Link*)0)->insert(NULL) might cause problems, no?
    Frankly, code like that shouldn't even compile.
  • jj 2009-05-15 17:55

    Boolean answer = new Boolean(
    inp.equals("true")
    ? new Boolean(true)
    : new Boolean(false)).booleanValue();


    This is even more amazing if you understand autoboxing and notice the operations the compiler will add in. The final result is something like


    Boolean answer = Boolean.valueOf(
    new Boolean(inp.equals("true")
    ? new Boolean(true).booleanValue()
    : new Boolean(false).booleanValue()
    ).booleanValue())


    wow.
  • voyou 2009-05-15 19:20
    paulm:
    SCJP:
    For those not familiar with Java:
    Boolean answer = new Boolean(inp);
    ...simply does the trick.


    Although,
    Boolean answer = Boolean.valueOf(inp);

    is even better, as it avoids pointlessly creating extra Boolean object instances.



    What's the difference? I would have thought they both created exactly one Boolean instance (but I don't have any great level of understanding of how Java's boxing works).
  • ratchetr 2009-05-15 20:24
    Loren Pechtel:
    The problem with the !this is not the test, it's what's done about it. On occasion it might make sense to return false if called on a null but that certainly shouldn't be the normal result. The desired result generally should be to die.

    Sudden death is hardly ever a good design decision. Software should degrade gracefully even when faced with impossible errors. (I'm assuming !this isn't an expected condition...that WOULD be a WTF.)

    What if the code in question is part of an engine management system? Do you want your car to just die while you're merging into rush hour traffic? Even if the class in quesion is CRearWiperControl and the function is EnableMotor()? return false works for me here.

    I've written a number of Windows services in my career, and 'just die' is never an option. (Same would apply to a *nix daemon process). The service/daemon should keep running, even it it hits an 'impossible' error processing a single request.

    Even in a simple web app, 'just die' isn't very elegant. The customer sees a blank page. Support has no clue what went wrong. Developers dismiss the bug report because they can't reproduce it.

    if(!this) return false; certainly is a WTF, but not because it's too defensive. It's not defensive enough. As already mentioned, you really want an assert here so you can catch these things during development. And throwing an exception is probably better than return false, assuming you have an exception handler in place somewhere up the stack. And make sure you log it if you can. assert is great but it disappears in your release build. Customers run release builds.

    So, to be pedantic:
    bool foo()
    {
    assert(this);
    if(!this) Log("NULL pointer passed to foo());
    if(!this) return false; // or throw new SomeException()
    }

    And since this is C++, you can bury all those details in some sort of VERIFYTHIS() macro if you are so inclined.









  • sota 2009-05-15 21:37
    lolwtf:
    Code Dependent:
    Blob:
    Jerry:
    Josh's predecessor seemed to miss out on the fundamentals the request/response paradigm.
    ... while Josh, in turn, missed out on the fundamentals the English grammar.
    "of" has been deprecated
    Yes, "the" is now used in its place.
    What a load the nonsense. I'd rant about it, but I have to log thef.


    I see what you did there.
  • SubSubDelimit 2009-05-16 03:31
    voyou:
    paulm:
    SCJP:
    For those not familiar with Java:
    Boolean answer = new Boolean(inp);
    ...simply does the trick.


    Although,
    Boolean answer = Boolean.valueOf(inp);

    is even better, as it avoids pointlessly creating extra Boolean object instances.



    What's the difference? I would have thought they both created exactly one Boolean instance (but I don't have any great level of understanding of how Java's boxing works).


    The original test included inp.equals("true") so probably inp is of type String.

    Boolean answer = inp.equals("true"); // autoboxing

    or even better

    Boolean answer = inp.equalsIgnoreCase("true");

  • paulm 2009-05-16 04:05
    voyou:
    What's the difference?


    Boolean.valueOf doesn't create any objects. The Boolean class has two static instances of Boolean (Boolean.TRUE and Boolean.FALSE). Boolean.valueOf returns one of the already existing objects.
  • Simon 2009-05-16 05:55
    Some C++ compilers, if told not to use exceptions, will not return a null pointer if new fails - that function is explicitly defined to return an exception on error. It mainly comes up if you're overriding the memory allocation / deallocation functions for some reason, eg to track leaks or to deliberately corrupt memory or simulate tight constraints to make the code more robust.

    What tends to happen, at least under gcc 4, is that you end up with the stupid compiler calling an object's constructor even on a failure, because it expects you to be throwing an exception to stop it instead. But if you've got a product that requires legacy platform support then you generally can't use exceptions because they're not supported by all older C++ compilers. Not to mention that they make it harder to read code, and much more difficult to isolate things like memory leaks if you're not careful.

    Thus there are perfectly legitimate situations where checking that the this pointer isn't null is necessary. Probably putting it everywhere is overkill but it certainly won't be something the optimiser will remove.
  • Weps 2009-05-16 05:58
    Pedant:
    Weps:
    Pedant:

    Bjarne Stroustrup uses "if (this==0)" twice on page 605 of "Programming: Principles and Practice using C++". It isn't needed in every method, but it isn't automatically a WTF.


    If he meant "if (this==NULL)" then it's definitly a wtf.


    What are you talking about? NULL and 0 are synonymous in C++.


    I guess you mean that NULL is defined as 0 (not always true), which is, I hope, done for a reason. Defining NULL, not it being equal to 0.

    Why not just say zero-pointer instead of null-pointer? Why invent the term null at all?

    Anyways, the wtf is knowing what the (pre)compiler makes of it and then applying that knowledge in the code, completely screwing any related human language agreement/convention.









  • Rob 2009-05-16 09:55
    The "if (!this) return false" case is checking for method calls on null pointers. It's paranoid, probably eliminates some optimizations, and doesn't work when multiple inheritance is involved.
  • dkf 2009-05-16 10:04
    Weps:
    Why not just say zero-pointer instead of null-pointer? Why invent the term null at all?
    The term “null” (used to indicate a pointer or reference that does not refer to an extant entity) has been around for a long time; it certainly predates C++ and may well predate C. In early systems, the null pointer was not necessarily a zero pointer; that's a later development...
  • Ahto 2009-05-16 10:59
    Weps:
    Pedant:
    Weps:
    Pedant:
    Bjarne Stroustrup uses "if (this==0)" twice on page 605 of "Programming: Principles and Practice using C++". It isn't needed in every method, but it isn't automatically a WTF.

    If he meant "if (this==NULL)" then it's definitly a wtf.

    What are you talking about? NULL and 0 are synonymous in C++.

    I guess you mean that NULL is defined as 0 (not always true), which is, I hope, done for a reason. Defining NULL, not it being equal to 0.

    Why not just say zero-pointer instead of null-pointer? Why invent the term null at all?

    Anyways, the wtf is knowing what the (pre)compiler makes of it and then applying that knowledge in the code, completely screwing any related human language agreement/convention.

    I guess you haven't really studied C++.

    Clause 4.10 of the current C++ standard says
    A null pointer constant is an integral constant expression (expr.const) rvalue of integer type that evaluates to zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (conv.qual).

    In fact, mostly the same holds for modern versions of C. Clause 6.3.2.3 of the current C standard says
    An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.[55] If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

    Your claim applies only in pre-ANSI standard versions of C.
  • SCJP 2009-05-16 11:29
    voyou:
    paulm:
    SCJP:
    For those not familiar with Java:
    Boolean answer = new Boolean(inp);
    ...simply does the trick.


    Although,
    Boolean answer = Boolean.valueOf(inp);

    is even better, as it avoids pointlessly creating extra Boolean object instances.



    What's the difference? I would have thought they both created exactly one Boolean instance (but I don't have any great level of understanding of how Java's boxing works).


    You're right. There's no "extra" instance. Just the one the reference of which is assigned to the variable.

    You only have the choice between...

    * ...creating the instance explicitly, as it always has been in Java (with new) and assigning its reference to a variable

    * ...performing some function (valueOf, equals, equalsIgnoreCase) assigning a primitive value to an object reference(!) and let Java's implicit often spurned autoboxing create the object and assign its reference to the variable

    * ...deciding which code is more readable and quicker
  • Loren Pechtel 2009-05-16 11:40
    ratchetr:
    Loren Pechtel:
    The problem with the !this is not the test, it's what's done about it. On occasion it might make sense to return false if called on a null but that certainly shouldn't be the normal result. The desired result generally should be to die.

    Sudden death is hardly ever a good design decision. Software should degrade gracefully even when faced with impossible errors. (I'm assuming !this isn't an expected condition...that WOULD be a WTF.)

    What if the code in question is part of an engine management system? Do you want your car to just die while you're merging into rush hour traffic? Even if the class in quesion is CRearWiperControl and the function is EnableMotor()? return false works for me here.

    I've written a number of Windows services in my career, and 'just die' is never an option. (Same would apply to a *nix daemon process). The service/daemon should keep running, even it it hits an 'impossible' error processing a single request.

    Even in a simple web app, 'just die' isn't very elegant. The customer sees a blank page. Support has no clue what went wrong. Developers dismiss the bug report because they can't reproduce it.

    if(!this) return false; certainly is a WTF, but not because it's too defensive. It's not defensive enough. As already mentioned, you really want an assert here so you can catch these things during development. And throwing an exception is probably better than return false, assuming you have an exception handler in place somewhere up the stack. And make sure you log it if you can. assert is great but it disappears in your release build. Customers run release builds.

    So, to be pedantic:
    bool foo()
    {
    assert(this);
    if(!this) Log("NULL pointer passed to foo());
    if(!this) return false; // or throw new SomeException()
    }

    And since this is C++, you can bury all those details in some sort of VERIFYTHIS() macro if you are so inclined.


    Throwing an exception *IS* a means of dying. Maybe something up the chain will handle it. Anything that *MUST* keep on going (your embedded systems example) certainly will handle it at the top.

    However, in general it's a lot better for a program to terminate than to continue on with obviously bad instructions.
  • SCJP 2009-05-16 11:57
    SCJP:
    * ...performing some function (valueOf, equals, equalsIgnoreCase) assigning a primitive value to an object reference(!) and let Java's implicit often spurned autoboxing create the object and assign its reference to the variable
    Correction: Boolean.valueOf returns a reference to the static Boolean.TRUE or Boolean.FALSE, so doesn't create a new object.
  • grumpy 2009-05-16 12:11
    Weps:

    I guess you mean that NULL is defined as 0 (not always true), which is, I hope, done for a reason. Defining NULL, not it being equal to 0.

    Why not just say zero-pointer instead of null-pointer? Why invent the term null at all?

    Anyways, the wtf is knowing what the (pre)compiler makes of it and then applying that knowledge in the code, completely screwing any related human language agreement/convention.


    Nope, the C++ standard explicitly states that the constant expression 0 is a null pointer. And that is why NULL is, and will always be, #define'd as 0.

    Where it gets funky is that a null pointer may not necessarily correspond to the *address* zero. But if you assign zero to a pointer, that pointer becomes a null pointer. Even if this operation is implemented by storing a non-zero address into the pointer. And that is why it is not called a zero-pointer. As far as the language is concerned, it is not "a pointer to the address zero", but "a pointer that points nowhere".

    "I invented the term Object-Oriented and I can tell you I did not have C++ in mind." -- Alan Kay

    That quote has always annoyed me. It is a fundamental misunderstanding to assume that C++ is *meant* to be an object-oriented language. He might as well have said that he didn't have LISP, Haskell or Prolog in mind when he invented the term. It'd be true, and pretty uninformative in either case.

    I think one of C++'s biggest strengths is that it is *not* a strict OOP language.
  • Pim 2009-05-16 13:08
    Pedant:
    The real WTF is that someone thinks that "!this" is a WTF in C++. Please do us a favor and stay far away from C++ until you learn what you are doing.

    Bjarne Stroustrup uses "if (this==0)" twice on page 605 of "Programming: Principles and Practice using C++". It isn't needed in every method, but it isn't automatically a WTF.
    But it's not safe! You're not protecting yourelf from anything if you test for !this. You only create a false sense of security. Look.

    myclass* p;
    p->function();

    A common mistake. Now since pointers are not automatically initialised to 0, the "this" in the function has a random value. It doesn't help to test for !this.
  • Matt.C 2009-05-16 13:41
    The best defense is a good offense!
  • Captain Oblivious 2009-05-16 13:44
    grumpy:

    "I invented the term Object-Oriented and I can tell you I did not have C++ in mind." -- Alan Kay

    That quote has always annoyed me. It is a fundamental misunderstanding to assume that C++ is *meant* to be an object-oriented language. He might as well have said that he didn't have LISP, Haskell or Prolog in mind when he invented the term. It'd be true, and pretty uninformative in either case.

    I think one of C++'s biggest strengths is that it is *not* a strict OOP language.


    I'm pretty sure he had LISP in mind, since the first object systems were written in LISP.

    C++ was meant to be an object oriented language with support for a templating type system. You can read all about it on Bjarne's homepage.

    http://www.research.att.com/~bs/oopsla.pdf

    The ironically titled paper "Why C++is not just an Object-Oriented Programming Language" explains why. Most of the features Bjarne says make C++ "not purely object oriented" are now considered object-oriented. From the abstract:

    This paper briefly presents key programming styles directly supported by
    C++and argues that the support for multiple styles is one of its major strengths. The styles presented include: traditional C-style, concrete classes, abstract
    classes, traditional class hierarchies, abstract classes and class hierarchies, and
    generic programming. To provide a context for this overview, I discuss criteria
    for a reasonable and useful definition of ‘‘object-oriented programming.’’


    Which of the features Bjarne pointed out as not being OO do you not consider OO? Keep in mind you can write "C-style" code in any language. Even Haskell, a purely functional language.

    Generic programming is merely quantification over classes.
  • 008 2009-05-16 14:00
    Pim:
    Pedant:
    The real WTF is that someone thinks that "!this" is a WTF in C++. Please do us a favor and stay far away from C++ until you learn what you are doing.

    Bjarne Stroustrup uses "if (this==0)" twice on page 605 of "Programming: Principles and Practice using C++". It isn't needed in every method, but it isn't automatically a WTF.
    But it's not safe! You're not protecting yourelf from anything if you test for !this. You only create a false sense of security. Look.

    myclass* p;
    p->function();

    A common mistake. Now since pointers are not automatically initialised to 0, the "this" in the function has a random value. It doesn't help to test for !this.


    While it may be true that !this does not catch wild pointers (which are not guaranteed to be null), you should be initializing your pointers explicitly anyway (via myclass* p=NULL;, myclass* p=new myclass(<insert ctor args here>);, myclass* p=SomeFunctionThatReturnsAMyclassPointer();, etc.).
  • Weps 2009-05-16 14:20
    I wrote "not always true" to indicate that in some versions NULL is defined as 0, and in some as a void* cast blabla something. It all means the same essentially. I know.

    Actually, I don't care what it is defined as, and neither should anybody. As long as I know that I can use NULL to test for null-pointers.

    But hey, I'm probably alone this....

    So to recap:

    Lets agree on pointers that point nowhere to call them null-pointers and not zero-pointers. Hell, let's make a define for NULL as well.

    And then, let's NOT use the define for NULL, but 0 in the code. Heck, it saves us 4 keypresses everytime!

    Hooray, we made things a lot more clearer now.

  • Pim 2009-05-16 14:29
    3!
  • Pim 2009-05-16 14:36
    008:
    Pim:
    myclass* p;
    p->function();

    A common mistake. Now since pointers are not automatically initialised to 0, the "this" in the function has a random value. It doesn't help to test for !this.

    While it may be true that !this does not catch wild pointers (which are not guaranteed to be null), you should be initializing your pointers explicitly anyway (via myclass* p=NULL;, myclass* p=new myclass(<insert ctor args here>);, myclass* p=SomeFunctionThatReturnsAMyclassPointer();, etc.).

    Yes. That's what you should do. And you should always call class members only when they're in valid instances. And you should refrain from using objects after "delete" has been called on the pointers to them.
    I know. We should, but we don't. We're all human.
    That's when defence mechanisms like that come in handy. I was just trying to say that it doesn't always work, and if people think it does, they're sticking their head in the sand.
  • Thuktun 2009-05-16 15:15
    if (!this) return false;
    As strange as it may sound, some versions of the Microsoft C++ compiler can have have a null this when you call a method on a null object pointer.

    Of course it might have been more helpful had it simply thrown an exception instead of masking the problem.
  • anon 2009-05-16 20:02
    grumpy:

    Where it gets funky is that a null pointer may not necessarily correspond to the *address* zero. But if you assign zero to a pointer, that pointer becomes a null pointer. Even if this operation is implemented by storing a non-zero address into the pointer. And that is why it is not called a zero-pointer. As far as the language is concerned, it is not "a pointer to the address zero", but "a pointer that points nowhere".

    Just out of curiosity: How do you create a pointer to address 0 -- and what happens if you decrement a pointer to address 1?
  • Pim 2009-05-17 03:57
    anon:
    Just out of curiosity: How do you create a pointer to address 0 -- and what happens if you decrement a pointer to address 1?

    First, read something like http://en.wikipedia.org/wiki/C_memory_model. Then, use a far pointer.

    To decrement a NULL pointer, it helps to think of pointers as unsigned. So they don't have -1. They can be 0xFFFF, 0xFFFFF or 0xFFFFFFFF, depending on the memory model. Or even more Fs, if you have 64 bit addres space.
    (What's the name of the 64 bit memory model? It must be bigger than "huge".)

    Addendum (2009-05-17 05:43):
    Oh, I see I misread your second question.
    If you have a long pointer to the physical address 1, decrementing it would result in the physical address 0. That's not so hard.

    On the other hand, you have to keep the environment in mind. For instance, your C compiler might start to complain loudly if you want to make a pointer to an address that is not on a doubleword boundary. Or decrementing it would result in 0xFFFFFFFD. (MSVC 8 does the latter, but has no problems with the former.)
  • Bellinghman 2009-05-17 08:30
    Weps:
    I wrote "not always true" to indicate that in some versions NULL is defined as 0, and in some as a void* cast blabla something.
    Well, that's the problem - you're incorrect. And starting from an incorrect premise, the rest of your argument is worthless.

    In C++, unlike in C, in no case is NULL permitted to be defined as a void*. This is explicitly stated in the standard.

    18.1 Types, para 4: "The macro NULL is an implementation-defined C++ null pointer constant in this International Standard
    (4.10).180)

    180) Possible definitions include 0 and 0L, but not (void*)0."


    The reason for this is that defining NULL as ((void*)0) would break a large proportion of existing code, since such simple statements as char* ptr = NULL; would break.
  • ysth 2009-05-17 09:44
    Pim:
    3!
    6
  • Henning Makholm 2009-05-17 12:13
    anon:
    Just out of curiosity: How do you create a pointer to address 0 -- and what happens if you decrement a pointer to address 1?

    That's implementation-defined as best -- everything that concerns actual addresses is.

    On most platforms that any programmer will ever meet, a null pointer is the same thing as a pointer to the address zero. It's just that the C standard does not guarantee that this will be the case, so an implementation that did it differently could still claim to implement ISO C.

    A hypothetical scenario where this might be desired would be if one had a platform where the system linker sometimes puts a variable at actual address zero (which arguably would be WTF, but imagine that we're stuck with the ABI). Because the address of a defined object must not be null, the C compiler would have to use another bit pattern for null pointers, for example by xoring with 0xFFFF at each cast between pointer and integer types.
  • Liel D 2009-05-17 12:42
    Long:
    shadowman:
    Tom:
    Someone explain to me the javascript one. Is the WTF that the comment and the if (!confirmed) don't match? I'm going crazy trying to see what is wrong with this (maybe just because it is Friday...)


    The whole function is an unnecessary wrapper around

    var confirmation = confirm(message);

    It doesn't add anything beyond that one line.


    What if confirm() returns FILE_NOT_FOUND?


    In JavaScript confirm() will always display "OK" / "Cancel" buttons and return TRUE or FALSE.
    If I got the last part of the Custom_Confirm function described earlier right it works as a reverse confirm (returns true on Cancel and false on OK).
    The sad fact is you can always use ! to check for the opposite response, writing a function for this is... utterly stupid in real world systems).
  • Liel D 2009-05-17 12:50
    Liel D:
    Long:
    shadowman:
    Tom:
    Someone explain to me the javascript one. Is the WTF that the comment and the if (!confirmed) don't match? I'm going crazy trying to see what is wrong with this (maybe just because it is Friday...)


    The whole function is an unnecessary wrapper around

    var confirmation = confirm(message);

    It doesn't add anything beyond that one line.


    What if confirm() returns FILE_NOT_FOUND?


    In JavaScript confirm() will always display "OK" / "Cancel" buttons and return TRUE or FALSE.
    If I got the last part of the Custom_Confirm function described earlier right it works as a reverse confirm (returns true on Cancel and false on OK).
    The sad fact is you can always use ! to check for the opposite response, writing a function for this is... utterly stupid in real world systems).


    Thinking a little bit more on the issue it seems to be a flaw in the User Interface thinking... confirm() should be used only to CONFIRM an action taken by the user, clicking Cancel should do exactly that (return false the the default action and therefor canceling it action).

    A simple use of this would be to confirm a link being clicked while a form has been edited but not saved ("You have unsaved changes, Dismiss and continue?")
  • Weps 2009-05-17 13:06
    Bellinghman:
    Weps:
    I wrote "not always true" to indicate that in some versions NULL is defined as 0, and in some as a void* cast blabla something.
    Well, that's the problem - you're incorrect. And starting from an incorrect premise, the rest of your argument is worthless.


    Wake me up when you find the premise. If ever.
  • Pim 2009-05-17 13:45
    Henning Makholm:
    On most platforms that any programmer will ever meet, a null pointer is the same thing as a pointer to the address zero.
    True, these days. But there was a time when a data pointer could be a 16-bit pointer into the 16-bit data segment, which didn't necessarily reside at physical location 0000:0000. I mean, an address like 3E00:0000 would be a NULL address.

    Henning Makholm:
    A hypothetical scenario where this might be desired would be if one had a platform
    Hypothetical? No, no. Real! 8086!

    Henning Makholm:
    the C compiler would have to use another bit pattern for null pointers, for example by xoring with 0xFFFF at each cast between pointer and integer types.
    So 65535 would become a NULL pointer? No, that's not how it works, sorry.
  • BUELL 2009-05-17 13:46
    Nice! I lol'd
  • Mr B 2009-05-17 17:12
    Ooops! I recognise that line of code (if !this). As far as I recall I was having an issue with an object being destroyed but still having a dangling pointer to one of the functions...

    You'll all be glad to know that I don't code much C/C++ these days :)
  • BLZ Bubb 2009-05-17 17:25
    IE6 still accounts for 15% of the traffic

    Or Opera 9.x masquerading as IE6
  • Henning Makholm 2009-05-17 19:55
    Pim:
    Henning Makholm:
    On most platforms that any programmer will ever meet, a null pointer is the same thing as a pointer to the address zero.
    True, these days. But there was a time when a data pointer could be a 16-bit pointer into the 16-bit data segment, which didn't necessarily reside at physical location 0000:0000. I mean, an address like 3E00:0000 would be a NULL address.

    I meant address zero within the relevant address space. Here the relevant address space (for the purposes of my remark) would be the default data segment.

    I consider the relevant point here to be which bits are written when a null pointer is stored in RAM. In the small-data 8086 models, a null pointer is still stored as an all-zero-bits. Sure, the default DS is used when accessing through the pointer, but because it is implicit, it can be ignored when discussing integer/pointer casts.

    If, on the other hand, we're speaking of physical addresses, all modern platforms which do virtual memory break the expectation that a null pointer references (physical) address zero.

    Henning Makholm:
    A hypothetical scenario where this might be desired would be if one had a platform
    Hypothetical? No, no. Real! 8086!

    Not quite. In 16-bit MS-DOS, for example even in small-data models it is perfectly safe to represent the null pointer as an all-zeroes value. Such a pointer, interpreted as an address, would point to the PSP and could never clash with the address of user-declared or heap-allocated C object. Therefore the 8086 is not an example of the kind I described.

    Henning Makholm:
    the C compiler would have to use another bit pattern for null pointers, for example by xoring with 0xFFFF at each cast between pointer and integer types.
    So 65535 would become a NULL pointer? No, that's not how it works, sorry.

    It's not how it works in MS-DOS, no. I didn't claim that either. I fail to see how representing a null pointer as all-ones at run time would make a C implementation non-conforming, assuming it was properly documented by that implementation.
  • Henning Makholm 2009-05-17 20:17
    In other words, what I think is the interesting question is whether
    #include <stdio.h>
    
    #include <inttypes.h>
    int main(void) {
    union { intptr_t i; void *p; } u;
    u.i=0; u.p=0;
    printf("%" PRIdPTR "\n", u.i);
    return 0;
    }
    will print 0 or some other number (ignoring the orthogonal question of the conformance of the type-punning here).
  • Mike5 2009-05-18 01:53
    Buddy:
    if (!this) return false;

    It's perfectly legitimate because it's entirely possible to cast NULL to an object and use it to call non-virtual functions. Not smart or safe, but you'll see it throughout MS code.

    E.g.

    HDC hdc = ((CDC *)NULL)->GetSafeHdc();

    Yet another gotcha of C++...


    Reminds me of a comment from one of the recent articles:
    xtremezone :

    Java does suck... The language semantics are a bitch (I wouldn't consider it quick to write, though perhaps I just have to learn "the Java way" first), the code is ugly (I wouldn't call it maintainable)


    Mike5
  • Cipher 2009-05-18 02:17
    will it still work if inp="WTF"?
  • immibis 2009-05-18 02:57
    if (!this) return false;

    actually might make sense. Consider the code:

    class MyClass
    {
    public:
    int a;
    void SetA() {a = 42;}
    };
    void main()
    {
    MyClass *p = NULL;
    p->SetA();
    }
  • bjolling 2009-05-18 03:30
    Matt.C:
    The best defense is a good offense!
    You can't score a goal if you don't have the ball!
  • Fubar 2009-05-18 06:12
    With proper stack fuck-ups, it is totally possible to have this pointer to be 0. I've seen it right before my very own eyes.

    The ingredients for the magic: Symbian + function-local TReqeustStatus + asynchronous function w/ this local TRequestStatus as parameter.
  • Manos 2009-05-18 06:22
    A null pointer is not a dangling pointer.
    A dangling pointer is one that has a non-Null value that is no longer valid i.e. the object that it points to is now deleted.
  • julmu 2009-05-18 07:20
    Charles400:
    "I was going over some code from a SDK released by you know who," Tammie Kong wrote. "There were a few questionable things in it, but then I found a single line that made me pause. I realize string.format() has its advantages and all, but this just seemed ridiculous."

    No, I don't know who. Who?
    Yes.
  • ath 2009-05-18 07:30
    Code Dependent:
    Blob:
    Jerry:
    Josh's predecessor seemed to miss out on the fundamentals the request/response paradigm.
    ... while Josh, in turn, missed out on the fundamentals the English grammar.
    "of" has been deprecated
    Yes, "the" is now used in its place.


    Yes, "lang.util.the" is now used in its place.

    Fixed that for you...
  • Bosluis 2009-05-18 08:07
    33?
  • fw 2009-05-18 08:11
    the real WTF is that 'nearly every function' in their C++ classes returns a boolean.
  • BK 2009-05-18 08:52
    The real WTF is that so many, apparently reasonable, people who wrote posts above never heard of undefined behaviour and still claim to know C++.

    C++ is doomed, but not because it is bad language. It's rather because most people using it have no clue and do not bother to lear, other than by reading sources written by other ignorants. And yes, Microsoft's own MFC sources are worst of all. Concepts of exception safety, const correctness or even some basics of the language itself never came to minds of people who wrote or maintain it. Or if they did, were pushed aside.

    Microsoft invented .NET because they have too many programmers incapable of using or learning C++. And C, for that matter.
  • Henning Makholm 2009-05-18 08:59
    BK:
    C++ is doomed, but not because it is bad language. It's rather because most people using it have no clue and do not bother to lear, other than by reading sources written by other ignorants.
    By that criterion, every programming language is doomed. Or will be doomed, as soon as it achieves widespead use.
  • wirthling 2009-05-18 09:12
    I understand the uselessness of that confirm function but can someone explain what the problem is with IE6 and "return false"? Under what conditions will IE6 f that s up? And what is the proper work around?
  • Marc 2009-05-18 10:31
    Buddy:
    if (!this) return false;
    It's perfectly legitimate because it's entirely possible to cast NULL to an object and use it to call non-virtual functions. Not smart or safe, but you'll see it throughout MS code.

    E.g.

    HDC hdc = ((CDC *)NULL)->GetSafeHdc();

    Yet another gotcha of C++...


    What's more, there are perfectly legitimate uses for it.

    Example:

    int format_fs(FileSys* fsobject)
    {
    // fsobject may be NULL!
    return fsobject->quickformat();
    }

    int FileSys::quickformat()
    {
    if (this==NULL)
    {
    // create new file system altogether
    // set default settings here, e.g. cluster size
    }
    else
    {
    // create file system with settings based on existing one
    }
    // generic format code here!
    }

    I guess the person who chalked this up as a WTF simply hadn't
    considered the possibility that 'this' CAN be NULL for valid reasons (Not saying that there isn't a cleaner way to write the above code).

    If in theory code may be called with a NULL 'this' pointer, I'd say it is better practice to check for it and throw an exception, rather than to segfault.
  • Cbuttius 2009-05-18 10:33
    BK:
    The real WTF is that so many, apparently reasonable, people who wrote posts above never heard of undefined behaviour and still claim to know C++.

    C++ is doomed, but not because it is bad language. It's rather because most people using it have no clue and do not bother to lear, other than by reading sources written by other ignorants. And yes, Microsoft's own MFC sources are worst of all. Concepts of exception safety, const correctness or even some basics of the language itself never came to minds of people who wrote or maintain it. Or if they did, were pushed aside.

    Microsoft invented .NET because they have too many programmers incapable of using or learning C++. And C, for that matter.


    C++ is doomed if anything because it is too difficult to write properly, plus the fact that computing moved forwards and C++ as a language could never keep up.

    That they are moving on to C++0x and have not included a standard threading library, that there is no standard ABI so strings are non-portable, never mind no standard GUI / graphics library and that they created obstruficated concepts of binding rather than an in-built foreach and lambdas are among the biggest WTFs.

    Read any book on C++ and the first thing it will probably teach you is writing early 80s looking console programs, and even then there is no standard way to capture the keyboard input without echoing it to the screen and waiting for the user to hit the return key.

  • Cbuttius 2009-05-18 10:49
    [quote user="ratchetrSo, to be pedantic:
    bool foo()
    {
    assert(this);
    if(!this) Log("NULL pointer passed to foo());
    if(!this) return false; // or throw new SomeException()
    }

    And since this is C++, you can bury all those details in some sort of VERIFYTHIS() macro if you are so inclined.
    [/quote]
    Firstly throw new SomeException() is not the correct way to throw an exception in C++.

    Secondly this is completely the wrong reason for using exceptions in C++. exceptions are there to catch environmental-errors, i.e. things that happen at runtime that you do not expect, eg a file terminating early or being invalidly formatted or a network connection going down or a failed connection to a database.

    For programming errors, i.e. to find bugs, you use asserts.

    Where you are correct is that dying is rarely the right option. Someone having an application die on them will lose all their work. For UNIX apps you can handle this by catching SIGSEGV and SIGBUS signals. For Windows it will generally throw an access violation exception which you can catch.

    The best you can often do in such a case is to save anything important and restart the process.

    From a user's point of view, it is a WTF of programming that your browser dies if one of the pages you visit has a bug on it. It should simply stop running the script... However this should be implemented by using a separate process to run the script which uses its own memory space. If this process fails to complete the main process should catch this and report that there was an error on the page. This would also prevent browser "hang" when one of your tabs is taking a long time to run. You should be able to switch tabs and work on something else whilst another process is handling this slow operation.


  • David 2009-05-18 12:31
    The C language allows that code to print any value.
    (Even assuming that 'void *' and 'uintptr_t' are both the same sized items.)
    Although the difficulties this place on the compiler, and the amount of code that assumes the NULL pointer is the zero bit pattern, mean that no sane implementations use a non-zero NULL.
  • alegr 2009-05-18 12:47
    BK:

    And yes, Microsoft's own MFC sources are worst of all. Concepts of exception safety, const correctness or even some basics of the language itself never came to minds of people who wrote or maintain it. Or if they did, were pushed aside.




    Keep in mind that MFC was first written for a compiler that didn't support exceptions at all, and had its own quirks. After that, you have to keep the core backward compatible somehow.
  • Jay 2009-05-18 12:52
    ratchetr:
    Loren Pechtel:
    The problem with the !this is not the test, it's what's done about it. On occasion it might make sense to return false if called on a null but that certainly shouldn't be the normal result. The desired result generally should be to die.

    Sudden death is hardly ever a good design decision. Software should degrade gracefully even when faced with impossible errors.

    ...

    What if the code in question is part of an engine management system? Do you want your car to just die while you're merging into rush hour traffic? Even if the class in quesion is CRearWiperControl and the function is EnableMotor()? return false works for me here.



    If by "die" Loren meant to stop running with no message or logging or anything, I agree that is rarely if ever the best solution. But I don't think that's what he meant. He meant "don't return an arbitrary value", i.e. DON'T "degrade gracefully", but display some sort of error message and die.

    Yes, sometimes degrading gracefully is the best thing to do. Like your example of the wiper motors not working. Sure, I'd rather my car keep running without windshield wipers.

    But suppose the software is a piece of medical monitoring equipment. If it loses the signal from the patient's heart beat sensor, should it just display a "default heart beat" and continue working? I think if I was the patient, I would much prefer that it display a nasty error message and alert everybody in sight that the system has failed.

    Note: The above discussion may or may not have anything to do with the specific function under discussion, as we don't know what it was supposed to do or what a return of "false" means.
  • EvanED 2009-05-18 13:44
    Weps:
    I wrote "not always true" to indicate that in some versions NULL is defined as 0, and in some as a void* cast blabla something. It all means the same essentially. I know.


    If your C++ compiler defines "NULL" to be "(void*)0", it's not compliant from the standard in two respects:

    1. The standard requires NULL to be defined as 0 or 0L

    2. The standard prohibits "foo* o = (void*)(anything)" from compiling, so "foo* o = NULL" wouldn't compile in that case.

    Actually, I don't care what it is defined as, and neither should anybody. As long as I know that I can use NULL to test for null-pointers.


    There is actually an argument to be made for not using NULL, which is that it can be misleading. There are some cases in C and C++ where writing correct code or recognizing what a program does requires acknowledging that NULL isn't actually a pointer -- something that using '0' makes explicit.

    For instance, consider three functions:
      foo(int * a);
    
    foo(char * a);
    foo(int a);

    and a function call
      foo(NULL);


    If NULL were actually a pointer, this call would be ambiguous because either foo(int * a) or foo(char * a) would apply equally well. In fact, the call is completely unambiguous in the worst way -- it calls foo(int a).

    Sure, the compiler will probably give a warning (at least GCC does, even without any additional -w flags), but depending on how studious you are about warnings, it could be easy to miss.

    Even in pure C, you have a leaky abstraction. Take 'int execl(const char *path, const char *arg, ...)' from Unix. You mark the end of the arg arrays with a null point.r

    Is "excel(path, arg0, arg1, arg2, NULL)" correct? Not technically. (Even if it will work on basically any reasonable platform.) Why? Because NULL isn't a pointer -- it's an integer. To be correct and portable even to Byzantine platforms, you have to say "(char*)NULL" for the final parameter.

    (There are equally good arguments for using NULL on other grounds, but the debate definitely isn't one-sided.)
  • voyou 2009-05-18 14:45
    EvanED:

    1. The standard requires NULL to be defined as 0 or 0L


    I think (I could be wrong) that the standard only requires that NULL be an constant of an integer type with value 0, so it could be defined as 3-3 or '\0'. Or it could be defined as some special magic integer value, in order to allow warnings when NULL is used in a non-pointer context (which is how G++ works).

    EvanED:

    There is actually an argument to be made for not using NULL, which is that it can be misleading. There are some cases in C and C++ where writing correct code or recognizing what a program does requires acknowledging that NULL isn't actually a pointer -- something that using '0' makes explicit.


    Indeed. And C++0x will include a separate null pointer value to avoid this problem (I assume, though, that NULL will still be defined as an integer for backwards compatibility).
  • EvanED 2009-05-18 15:01
    voyou:
    EvanED:

    1. The standard requires NULL to be defined as 0 or 0L


    I think (I could be wrong) that the standard only requires that NULL be an constant of an integer type with value 0, so it could be defined as 3-3 or '\0'. Or it could be defined as some special magic integer value, in order to allow warnings when NULL is used in a non-pointer context (which is how G++ works).


    Yeah, I think you're right. (Regardless, (void*)0 is out.)


    Indeed. And C++0x will include a separate null pointer value to avoid this problem (I assume, though, that NULL will still be defined as an integer for backwards compatibility).


    I almost edited my post to include mention of nullptr, but was too slow and just missed the 5 minute window. ;-)

    (And NULL will continue to be available.)
  • Jason 2009-05-18 20:14
    Believe it or not, this code would prevent a crash when calling a virtual function on a null pointer. This is not a good way to deal with this, so still WTF.
  • Rhialto 2009-05-19 08:55
    Henning Makholm:
    A hypothetical scenario where this might be desired would be if one had a platform where the system linker sometimes puts a variable at actual address zero (which arguably would be WTF, but imagine that we're stuck with the ABI). Because the address of a defined object must not be null, the C compiler would have to use another bit pattern for null pointers, for example by xoring with 0xFFFF at each cast between pointer and integer types.

    The compiler doesn't have to do anything like that on all such conversions. Since only constant integral expressions with value 0 are convertible to null pointers, it only needs to do it for that case. If it encounters, say, (char *)(x - x), it can validly produce a non-null pointer.
  • Prometheus 2009-05-19 13:01
    if (!fist) return uppercut;

    CAPTCHA: aptent
    I think i know what I'm gonna call my next iphone app.
  • chrismcb 2009-05-19 21:37
    Jamie:
    OldCoder:
    SCJP:
    shadowman:
    I don't get the String.format() one.
    Splitting the SQL string into four parts first and let String.Format() put it together afterwards is somehow senseless.

    D'oh! You don't need the SQL at all, since all it selects is two fields which are the same as the values it supplies.


    You do if you want to find out if it is actually in the database... But that's not the way to do it!


    So I am no SQL Guru. So how would one find all of the user ids in a table where uid1=ID1 and uid2=ID2?
    Granted we will ONLY find those IDs and not the rest of the row.

    You know I still think ID's looks WAY better than IDs.
  • Cbuttius 2009-05-20 06:38
    Jason:
    Believe it or not, this code would prevent a crash when calling a virtual function on a null pointer. This is not a good way to deal with this, so still WTF.


    but this class might either not have any virtual functions or not do the test on one.
  • saluto 2009-05-21 08:50
    julmu:
    Charles400:
    No, I don't know who. Who?
    Yes.

    Hey, you're not Kosh!
  • tgape 2009-05-21 21:54
    DaveK:

    the actual code and it was a even more surprising than I had remembered."

    #define NEGATIVE_ONE 0

    What's surprising about that? When it comes to boolean values, zero is the negative one. And '1' is the positive one. See?


    Apparently, according to what I overheard in the supermarket the other day, it should've been

    #define NEGATIVE_NANCY 0
  • Pim 2009-05-23 04:59


    Addendum (2009-05-23 05:05):


    Addendum (2009-05-23 05:05):
    Oh, I see the Delete button doesn't work for these messages. Darn. Sorry about the mess.
  • Brad D 2009-05-29 15:32
    This one looks like just your basic case of somebody adding some debug code and forgetting to take it out before putting it into production. A good argument for code reviews, I suppose.
  • Brad D 2009-05-29 15:40
    chrismcb:
    Jamie:
    OldCoder:
    SCJP:
    shadowman:
    I don't get the String.format() one.
    Splitting the SQL string into four parts first and let String.Format() put it together afterwards is somehow senseless.

    D'oh! You don't need the SQL at all, since all it selects is two fields which are the same as the values it supplies.


    You do if you want to find out if it is actually in the database... But that's not the way to do it!


    So I am no SQL Guru. So how would one find all of the user ids in a table where uid1=ID1 and uid2=ID2?
    Granted we will ONLY find those IDs and not the rest of the row.

    You know I still think ID's looks WAY better than IDs.

    What you're seeing is probably the effect of a slightly lazy fix for a SQL injection bug(http://en.wikipedia.org/wiki/SQL_Injection). Probably the code originally had variable references instead of the "@" strings, and when they moved the value into a parameter array, they decided not to convert the whole statement to a string.

    to avoid the problem of people providing user ids like "' from table ; drop table accounting --"
  • Bluedive 2009-06-10 05:03
    "I was going over some code from a SDK released by you know who,"
    Voldemort?
  • Anonymous 2009-06-11 19:40
    Or they were trying to protect against dereferencing a null pointer. On a non-virtual function you can call a method on a null instance. It will fail when the function tries to access members. If it never accesses any members it will actually run just fine. (Or at least it would using old sun forte compilers on solaris 8.)