Comment On Defensive Programming and a Whole Lot More

"Some programmers like to program defensively," wrote Sam, "and then there's some of my coworkers. This is found at the top of nearly every function of our C++ classes." [expand full text]
« PrevPage 1 | Page 2 | Page 3Next »

Re: I don't see Andy Goth's problem

2009-05-17 13:46 • by BUELL (unregistered)
262959 in reply to 262745
Nice! I lol'd

Re: Defensive Programming and a Whole Lot More

2009-05-17 17:12 • by 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 :)

Re: Defensive Programming and a Whole Lot More

2009-05-17 17:25 • by BLZ Bubb (unregistered)
262968 in reply to 262712
IE6 still accounts for 15% of the traffic

Or Opera 9.x masquerading as IE6

Re: Defensive Programming and a Whole Lot More

2009-05-17 19:55 • by Henning Makholm (unregistered)
262974 in reply to 262958
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.

Re: Defensive Programming and a Whole Lot More

2009-05-17 20:17 • by Henning Makholm (unregistered)
262975 in reply to 262974
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).

Re: Defensive Programming and a Whole Lot More

2009-05-18 01:53 • by Mike5 (unregistered)
263009 in reply to 262704
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

Re: Defensive Programming and a Whole Lot More

2009-05-18 02:17 • by Cipher (unregistered)
263011 in reply to 262743
will it still work if inp="WTF"?

Re: Defensive Programming and a Whole Lot More

2009-05-18 02:57 • by immibis
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();
}

Re: Defensive Programming and a Whole Lot More

2009-05-18 03:30 • by bjolling
263017 in reply to 262909
Matt.C:
The best defense is a good offense!
You can't score a goal if you don't have the ball!

Re: Defensive Programming and a Whole Lot More

2009-05-18 06:12 • by 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.

Re: Defensive Programming and a Whole Lot More

2009-05-18 06:22 • by Manos
263130 in reply to 262966
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.

Re: Defensive Programming and a Whole Lot More

2009-05-18 07:20 • by julmu
263133 in reply to 262724
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.

Re: Defensive Programming and a Whole Lot More

2009-05-18 07:30 • by ath (unregistered)
263134 in reply to 262690
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...

Re: Defensive Programming and a Whole Lot More

2009-05-18 08:07 • by Bosluis (unregistered)
263135 in reply to 262945
33?

Re: Defensive Programming and a Whole Lot More

2009-05-18 08:11 • by fw (unregistered)
the real WTF is that 'nearly every function' in their C++ classes returns a boolean.

Re: Defensive Programming and a Whole Lot More

2009-05-18 08:52 • by 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.

Re: Defensive Programming and a Whole Lot More

2009-05-18 08:59 • by Henning Makholm (unregistered)
263139 in reply to 263138
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.

Re: Defensive Programming and a Whole Lot More

2009-05-18 09:12 • by 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?

Re: Defensive Programming and a Whole Lot More

2009-05-18 10:31 • by Marc (unregistered)
263179 in reply to 262704
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.

Re: Defensive Programming and a Whole Lot More

2009-05-18 10:33 • by Cbuttius (unregistered)
263180 in reply to 263138
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.

Re: Defensive Programming and a Whole Lot More

2009-05-18 10:49 • by Cbuttius (unregistered)
263187 in reply to 262807
[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.


Re: Defensive Programming and a Whole Lot More

2009-05-18 12:31 • by David (unregistered)
263209 in reply to 262975
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.

Re: Defensive Programming and a Whole Lot More

2009-05-18 12:47 • by alegr
263216 in reply to 263138
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.

Re: Defensive Programming and a Whole Lot More

2009-05-18 12:52 • by Jay (unregistered)
263217 in reply to 262807
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.

Re: Defensive Programming and a Whole Lot More

2009-05-18 13:44 • by EvanED
263224 in reply to 262913
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.)

Re: Defensive Programming and a Whole Lot More

2009-05-18 14:45 • by voyou (unregistered)
263233 in reply to 263224
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).

Re: Defensive Programming and a Whole Lot More

2009-05-18 15:01 • by EvanED
263235 in reply to 263233
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.)

Re: Defensive Programming and a Whole Lot More

2009-05-18 20:14 • by Jason (unregistered)
263247 in reply to 262677
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.

Re: Defensive Programming and a Whole Lot More

2009-05-19 08:55 • by Rhialto (unregistered)
263356 in reply to 262949
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.

Re: Defensive Programming and a Whole Lot More

2009-05-19 13:01 • by Prometheus (unregistered)
263437 in reply to 262659
if (!fist) return uppercut;

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

Re: Defensive Programming and a Whole Lot More

2009-05-19 21:37 • by chrismcb
263534 in reply to 262769
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.

Re: Defensive Programming and a Whole Lot More

2009-05-20 06:38 • by Cbuttius (unregistered)
263622 in reply to 263247
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.

Re: Defensive Programming and a Whole Lot More

2009-05-21 08:50 • by saluto (unregistered)
264605 in reply to 263133
julmu:
Charles400:
No, I don't know who. Who?
Yes.

Hey, you're not Kosh!

Re: I don't see Andy Goth's problem

2009-05-21 21:54 • by tgape
264820 in reply to 262745
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

Re: Defensive Programming and a Whole Lot More

2009-05-23 04:59 • by Pim
265088 in reply to 264605


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.

Re: Defensive Programming and a Whole Lot More

2009-05-29 15:32 • by Brad D (unregistered)
266355 in reply to 262710
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.

Re: Defensive Programming and a Whole Lot More

2009-05-29 15:40 • by Brad D (unregistered)
266356 in reply to 263534
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 --"

Re: Defensive Programming and a Whole Lot More

2009-06-10 05:03 • by Bluedive
"I was going over some code from a SDK released by you know who,"
Voldemort?

Re: Defensive Programming and a Whole Lot More

2009-06-11 19:40 • by Anonymous (unregistered)
268799 in reply to 262677
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.)
« PrevPage 1 | Page 2 | Page 3Next »

Add Comment