• BUELL (unregistered) in reply to DaveK

    Nice! I lol'd

  • Mr B (unregistered)

    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 (unregistered) in reply to Rootbeer

    IE6 still accounts for 15% of the traffic

    Or Opera 9.x masquerading as IE6

  • Henning Makholm (unregistered) in reply to Pim
    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 (unregistered) in reply to Henning Makholm

    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 (unregistered) in reply to Buddy
    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 (unregistered) in reply to SCJP

    will it still work if inp="WTF"?

  • (cs)
    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();
    }
    
  • (cs) in reply to Matt.C
    Matt.C:
    The best defense is a good offense!
    You can't score a goal if you don't have the ball!
  • Fubar (unregistered)

    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.

  • (cs) in reply to Mr B

    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.

  • (cs) in reply to Charles400
    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 (unregistered) in reply to Code Dependent
    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 (unregistered) in reply to ysth

    33?

  • fw (unregistered)

    the real WTF is that 'nearly every function' in their C++ classes returns a boolean.

  • BK (unregistered)

    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 (unregistered) in reply to BK
    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 (unregistered)

    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 (unregistered) in reply to Buddy
    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 (unregistered) in reply to BK
    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 (unregistered) in reply to ratchetr

    [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 (unregistered) in reply to Henning Makholm

    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.

  • (cs) in reply to BK
    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 (unregistered) in reply to ratchetr
    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.

  • (cs) in reply to Weps
    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 (unregistered) in reply to EvanED
    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).

  • (cs) in reply to voyou
    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 (unregistered) in reply to kastein

    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 (unregistered) in reply to Henning Makholm
    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 (unregistered) in reply to Code Dependent

    if (!fist) return uppercut;

    CAPTCHA: aptent I think i know what I'm gonna call my next iphone app.

  • (cs) in reply to Jamie
    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 (unregistered) in reply to Jason
    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 (unregistered) in reply to julmu
    julmu:
    Charles400:
    No, I don't know who. Who?
    Yes.
    Hey, you're not Kosh!
  • (cs) in reply to DaveK
    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
    
  • (cs) in reply to saluto

    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 (unregistered) in reply to methinks

    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 (unregistered) in reply to chrismcb
    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 --"

  • (cs)
    "I was going over some code from a SDK released by you know who,"
    Voldemort?
  • Anonymous (unregistered) in reply to kastein

    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.)

Leave a comment on “Defensive Programming and a Whole Lot More”

Log In or post as a guest

Replying to comment #:

« Return to Article