Do you check for errors with "< 0" or "== -1"?

Do you check for errors with "< 0" or "== -1"?

Post by Marc Rochkin » Fri, 27 Sep 2002 02:42:30



This is a discussion question.

I see this a lot, even in books:

if ((fd = open(...)) < 0) {
    ... deal with error using errno ...

Quote:}

rather than this:

if ((fd = open(...)) == -1) {
    ... deal with error using errno ...

Quote:}

It seems to me the the second way is better because:

1. The standard says that -1 is returned on an error (not < 0) and also that
errno is undefined for any other return.

2. For some functions that return * things like process IDs or
message-queue IDs, if there is a check for < 0 coded instead of the
documented -1 (perhaps with a cast to, say, mqd_t), a reader (especially one
looking for a bug, or checking for conformance to the standard) has to know
whether the range of the return value includes negative numbers. This seems
to me to be unnecessary mental clutter. Why should one have to answer UNIX
trivia questions when there is so much to do and so little time? If the
constant is precisely what the standard says, it is straightforward to
verify that the code is right.

3. One needs more precision for error detection than for the normal-return
case, because the latter is executed all the time, and the former only
rarely occurs and in some cases can't even be tested. So (related to point
#2), a lot of the "testing" involves code reading, not running test cases.

4. Someday the function could be changed, and the standards writers, knowing
they had been saying -1 all along, would think that using other negative
numbers for a normal return would be upward compatible. (A lousy idea, sure,
but they've done worse things.)

My guess is that programmers who code "< 0" are just trying to be defensive.
But why? The standard clearly says -1, so what is one defending against?

I'd love to hear opposing points of view, and I'm sure you all will oblige!
:-)

--Marc

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Niall Kavanag » Fri, 27 Sep 2002 04:24:58



> This is a discussion question.
> I see this a lot, even in books:
> if ((fd = open(...)) < 0) {
>     ... deal with error using errno ...
> }
> rather than this:
> if ((fd = open(...)) == -1) {
>     ... deal with error using errno ...
> }

I imagine because a valid file descriptor is a non-negative integer, and
anything else is an error condition? Seems a lot more bullet proof to me
than trusting the standard has been followed/implemented correctly in
every situation.

--
dev

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Marc Rochkin » Fri, 27 Sep 2002 05:22:21


Quote:> I imagine because a valid file descriptor is a non-negative integer, and
> anything else is an error condition? Seems a lot more bullet proof to me
> than trusting the standard has been followed/implemented correctly in
> every situation.

Open was only an example. The general issue I was trying to raise was
following the standard (or the documentation) vs. an approximation of it.
 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Bill Medlan » Fri, 27 Sep 2002 05:28:38



Quote:> This is a discussion question.

> I see this a lot, even in books:

> if ((fd = open(...)) < 0) {
>     ... deal with error using errno ...
> }

> rather than this:

> if ((fd = open(...)) == -1) {
>     ... deal with error using errno ...
> }

> It seems to me the the second way is better because:

> 1. The standard says that -1 is returned on an error (not < 0) and also
that
> errno is undefined for any other return.

> 2. For some functions that return * things like process IDs or
> message-queue IDs, if there is a check for < 0 coded instead of the
> documented -1 (perhaps with a cast to, say, mqd_t), a reader (especially
one
> looking for a bug, or checking for conformance to the standard) has to
know
> whether the range of the return value includes negative numbers. This
seems
> to me to be unnecessary mental clutter. Why should one have to answer UNIX
> trivia questions when there is so much to do and so little time? If the
> constant is precisely what the standard says, it is straightforward to
> verify that the code is right.

> 3. One needs more precision for error detection than for the normal-return
> case, because the latter is executed all the time, and the former only
> rarely occurs and in some cases can't even be tested. So (related to point
> #2), a lot of the "testing" involves code reading, not running test cases.

> 4. Someday the function could be changed, and the standards writers,
knowing
> they had been saying -1 all along, would think that using other negative
> numbers for a normal return would be upward compatible. (A lousy idea,
sure,
> but they've done worse things.)

> My guess is that programmers who code "< 0" are just trying to be
defensive.
> But why? The standard clearly says -1, so what is one defending against?

Which consequence would you prefer?  It is a risk question.

If one specifies that on getting back a negative value one should treat it
as an error then hopefully (if the error recovery has been written robustly)
the returned "handle" will not be used if it happens to be a negative value
other than -1.  However if one specifies -1 only then, should an
implementation be bad etc., the code would go ahead and use the bad handle
(which should, of course, be detected by the system).

As far as I am concerned all three possible return states should be
addressed, with the impossible one being the last treated.  I guess the best
way is probably

if ((fd = open () ) >= 0) {
    perform_success_operation();

Quote:} else if (fd == -1) {

    perform_errno_handling();
Quote:} else {

    perform_impossible_handling(); /* at least assert(0) */

Quote:}

> I'd love to hear opposing points of view, and I'm sure you all will
oblige!
> :-)

> --Marc

Bill
 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Marc Rochkin » Fri, 27 Sep 2002 05:47:53


Quote:> As far as I am concerned all three possible return states should be
> addressed, with the impossible one being the last treated.

[stuff above and below deleted]

Makes sense... I wonder if anybody actually does this? The assertion on the
"impossible" state guards against an updated version someday falling into
that territory.

Still, for some non-int types (e.g., mqd_t), it requires research to figure
out the integer range that's used, and then one has to check all the
standards to see if it's the same for all.

--Marc

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Eric Sosma » Fri, 27 Sep 2002 06:07:21



> > I imagine because a valid file descriptor is a non-negative integer, and
> > anything else is an error condition? Seems a lot more bullet proof to me
> > than trusting the standard has been followed/implemented correctly in
> > every situation.

> Open was only an example. The general issue I was trying to raise was
> following the standard (or the documentation) vs. an approximation of it.

    Test for what's advertised, and not for what isn't.

    It seems likely that the non-negativeness of file descriptors is
so deeply ingrained in Unix that it'll never change; a test for <0
will probably remain functionally equivalent to ==-1 for as long as
Unix is with us.

    But there are areas where change may be more likely.  Each passing
day brings us nearer to 2038 and the moment when a signed 32-bit time_t
will no longer suffice.  Some people think "just make time_t 64 bits"
solves the problem by magic, but others worry about 32-bit slots already
written on disks inside inodes and the like.  One intriguing approach
that buys another sixty-eight years is to leave time_t as a 32-bit
number, but make it unsigned: (time_t)-1 becomes the large positive
value 0xFFFFFFFF instead of a negative value, and in 2038 the clock
will advance from 0x7FFFFFFF to 0x80000000 to 0x80000001 without a
murmur ...

    ... provided, of course, that nobody checks for mktime() errors
and the like by testing whether the returned time_t is <0 ...

    Test for what's advertised, and not for what isn't.

--

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Rich Tee » Fri, 27 Sep 2002 07:07:15



> 1. The standard says that -1 is returned on an error (not < 0) and also that
> errno is undefined for any other return.

For functions (the majority) that are defined like this,
I test for -1.  Some other functions are more vague, and
say something like "non-zero is returned on error".  For
those, I test for != 0.

Quote:> I'd love to hear opposing points of view, and I'm sure you all will oblige!
> :-)

Not an opposing point of view (I agree with what you wrote),
but hopefully it might shed some more light on the matter.

--
Rich Teer

President,
Rite Online Inc.

Voice: +1 (250) 979-1638
URL: http://www.rite-online.net

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by M?ns Rullg? » Fri, 27 Sep 2002 09:48:16




> > > I imagine because a valid file descriptor is a non-negative integer, and
> > > anything else is an error condition? Seems a lot more bullet proof to me
> > > than trusting the standard has been followed/implemented correctly in
> > > every situation.

> > Open was only an example. The general issue I was trying to raise was
> > following the standard (or the documentation) vs. an approximation of it.

>     Test for what's advertised, and not for what isn't.

I usually say <0 in the documentation for things I write.  That way
I'm free to change later and eg. return different negative values
depending on the error without breaking any code.

Quote:>     But there are areas where change may be more likely.  Each passing
> day brings us nearer to 2038 and the moment when a signed 32-bit time_t
> will no longer suffice.  Some people think "just make time_t 64 bits"
> solves the problem by magic, but others worry about 32-bit slots already
> written on disks inside inodes and the like.


Sat Aug 16 19:31:21 CET 2319


-rw-r--r--    1 mru      users           0 Aug 16  2319 foo

Dates past 2038 are handled well here, with sizeof(time_t) == 8.

--
M?ns Rullg?rd

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Rich Tee » Fri, 27 Sep 2002 10:39:39



Quote:> I'm free to change later and eg. return different negative values
> depending on the error without breaking any code.

Isn't that what errno is for?

--
Rich Teer

President,
Rite Online Inc.

Voice: +1 (250) 979-1638
URL: http://www.rite-online.net

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by M?ns Rullg? » Fri, 27 Sep 2002 20:09:23



> > I'm free to change later and eg. return different negative values
> > depending on the error without breaking any code.

> Isn't that what errno is for?

errno is for the system call wrappers, eg. open and write.  When
dealing with multiple threads simply returning the error code directly
is much more convinient.

--
M?ns Rullg?rd

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Marc Rochkin » Fri, 27 Sep 2002 22:44:42


Quote:> I usually say <0 in the documentation for things I write.  That way
> I'm free to change later and eg. return different negative values
> depending on the error without breaking any code.

< 0 (as documented) sounds great, but, it's yet another animal added to the
zoo we already have, because the newer POSIX stuff returns > 0 on error.
 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Niall Kavanag » Sat, 28 Sep 2002 00:40:24



>> I imagine because a valid file descriptor is a non-negative integer, and
>> anything else is an error condition? Seems a lot more bullet proof to me
>> than trusting the standard has been followed/implemented correctly in
>> every situation.
> Open was only an example. The general issue I was trying to raise was
> following the standard (or the documentation) vs. an approximation of it.

Right, I was just responding to the specific example you gave. Interesting
thread so far... I've yet to see anyone do more than one of the
possibilities you put forth in your original email in the real world. I
suppose that if I'm not testing for -1 I should not count on errno being
valid when open returns a non-negative value; so I really should test for
both.

In your example, I would test for < 0 because I'm testing for a valid fd,
and not testing for adherence to a spec. If there's a possibility that
something is going to act up and I can test for it without doing
something hokey... I'll do it.
Though if I am completely honest I probably do this sort of thing because
that's how I've seen other folks do it.

--
dev

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Marc Rochkin » Sat, 28 Sep 2002 05:09:52



Quote:> In your example, I would test for < 0 because I'm testing for a valid fd,
> and not testing for adherence to a spec. If there's a possibility that
> something is going to act up and I can test for it without doing
> something hokey... I'll do it.

Yes, as someone else mentioned, isolating the "impossible" file descriptor
case could be defended, but you  can't just make the test "< 0" to do it,
because errno is only defined in the "-1" case.

--Marc

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Martin Dicko » Sat, 28 Sep 2002 05:23:00



> As far as I am concerned all three possible return states should be
> addressed, with the impossible one being the last treated.  I guess the best
> way is probably

> if ((fd = open () ) >= 0) {
>    perform_success_operation();
> } else if (fd == -1) {
>    perform_errno_handling();
> } else {
>    perform_impossible_handling(); /* at least assert(0) */
> }

You might want to code it like this, to get a more meaningful message
should the assert() fail:

fd = open (...);
assert (fd >= -1);
if (fd >= 0) { ... }
else { ... }

Anyway, I disagree that this should be done at all. Essentially, you
are testing for a bug in the implementaion of open(). IMHO, this should
be done in the implementaion of open(), not in user code. If you test
for all possible C library or kernel bugs in user code, your code will
be very cluttered.

Martin

 
 
 

Do you check for errors with "< 0" or "== -1"?

Post by Bill Medlan » Sat, 28 Sep 2002 07:25:28




> > As far as I am concerned all three possible return states should be
> > addressed, with the impossible one being the last treated.  I guess the
best
> > way is probably

> > if ((fd = open () ) >= 0) {
> >    perform_success_operation();
> > } else if (fd == -1) {
> >    perform_errno_handling();
> > } else {
> >    perform_impossible_handling(); /* at least assert(0) */
> > }

> You might want to code it like this, to get a more meaningful message
> should the assert() fail:

Yes, if I was only going to assert.  However for something like this I would
probably have release-version protection. (which of course presupposes that
I don't use assertion in release version code)

Quote:

> fd = open (...);
> assert (fd >= -1);
> if (fd >= 0) { ... }
> else { ... }

> Anyway, I disagree that this should be done at all. Essentially, you
> are testing for a bug in the implementaion of open().

yes

Quote:> IMHO, this should
> be done in the implementaion of open(), not in user code.

which assumes that the programmer has the ability to do that

Quote:> If you test
> for all possible C library or kernel bugs in user code, your code will
> be very cluttered.

It will certainly be big but it doesn't have to be cluttered.

And if you don't then you are one day going to be caught by a function that
does something other than what the documentation says it does and it is
going to take a while to find out what went wrong.

I am sure you have met the people who talk about a bug in the code when what
they mean is the visual failure that they can actually see that was the
consequence of something that happened unexpectedly a few thousand
instructions earlier.  And how about the "bugs" that only occur when the
moon is up and the computer is at the clients site and ....

Quote:

> Martin

Bill