crashing qsort

C

CBFalconer

Keith said:
Sorry, but I think treating NULL as "" is counterintuitive -- enough
so that it's nearly likele to cause a blackout as to prevent one.

If you want to program defensively, I suggest aborting on NULL rather
than silently hiding the client's error.

Well, I showed (for my strlcpy) how easy it was to change. I
still think it is ridiculous to accept erroneous inputs when they
can be given a reasonable interpretation. Aborting should not be
an option - a better interface would return an error indicator,
but such is not available for strlcpy.

I know my attitude is correct :) I just don't seem to be able to
find the right arguments to convince others of it. Maybe this
should drift to religious wars about formatting style. :) I
think I'll just go throw a tantrum.
 
M

Mark Gordon

Well, I showed (for my strlcpy) how easy it was to change. I
still think it is ridiculous to accept erroneous inputs when they
can be given a reasonable interpretation. Aborting should not be
an option - a better interface would return an error indicator,
but such is not available for strlcpy.

I know my attitude is correct :) I just don't seem to be able to
find the right arguments to convince others of it. Maybe this
should drift to religious wars about formatting style. :) I
think I'll just go throw a tantrum.

With the stuff I currently work on I would always prefer the application
to abort if a dodgy library call is made. That way the user reports it
to us, we fix it and no data is corrupted.

On the projects I've worked on in the past, embedded avionics systems
for example, I would prefer the library call to do the best it could so
that the application continues to run to the best of its ability, except
when I'm testing/debugging it in which case I want it to fail horribly
as quickly as possible.

The right thing to do on erroneous input to a function is very
application dependant.
 
P

Programmer Dude

CBFalconer said:
I know my attitude is correct :) I just don't seem to be able to
find the right arguments to convince others of it.

Well,... I don't know if this helps or hurts your position, but
I agree with you, and my library code often treats a const char*
argument as "" if passed NULL.

My reasoning is simple: I can't AT ALL count on what happens if I
ignore a NULL value and use it. If I *could* my stance might change.

Also I want my library code to be bullet-proof and NOT CAPABLE of
causing a crash (or nasal issuance). I do not consider it the
libraries domain to troubleshoot client code.

Further, in many cases (at least in my code), a NULL char* pointer
has a "no string" semantic, and I consider that very close to an
empty string. Close enough to treat it thus in a "strlen" function
or "strcpy" function.
 
P

Programmer Dude

Arthur J. O'Dwyer said:
I feel compelled to reiterate my opinion that

strcpy(s1, NULL)

really has no reasonable meaning.

No, but if the second argument is a variable (that may sometimes
be NULL), it does. The point is, often a char* variable has the
general semantic of "string or NULL" with NULL meaning "no string
YET assigned" or "string was optional" or like that. In such a
case, NULL == "" is not a far stretch, particularly when checking
length or copying.
(And what do you think of this one? UB again?)

strcpy(NULL, NULL)

That's why I said "const char*". You'd need to return NULL on
that one.
Aren't those two goals contradictory?

Imagine they aren't and go from there. (-:
If you want to bullet-proof your library code, then you do need
to check for NULLs and whatnot (thus effectively "troubleshooting"
whatever junk the client code throws at you).

Perhaps that is a side effect, but the check is to *protect* the
lib code from being able to invoke unknowable behavior.
I prefer not to troubleshoot the client's code, either. I think
that's the client's job. If he passes NULL to something that
doesn't expect NULL (and he knows it), then he's being foolish
and can troubleshoot his own dang code. :)

IME (which means both In My Experience and In My Environment), a
crash is *more* likely if you use the NULL than if you pretend it's
an empty string. The behavior of the system may be unexpected
(leading you to go troubleshooting), but (again, IME) that behavior
is preferrable to crashing (much of my code runs on production
lines that must not crash).

If I could be certain there were no bugs in the client code, it
wouldn't be a concern. But since that certainty is impossible,
I *must* (IMO) do what I can to prevent crashes. For me, that
means making a "best effort" with all data passed to me.
[Probably different meanings for the word "troubleshoot."
I'm using it in the sense of "fix the errors post-facto,"
as distinct from "prevent" ("stop errors from happening")
or "ignore" ("ignore").]

So am I. The opinion expressed when I had this debate previously
was that by using the NULL, you crash and alert the programmer to
the problem (allowing her to troubleshoot it). If I could be
100% certain this would always occur *during* development, then
I'd probably change my view.

Obviously I can't be 100% certain, so I try to make the library
code as crash-resistant as possible.
 
P

pete

Arthur said:

I feel compelled to reiterate my opinion that

strcpy(s1, NULL)

really has no reasonable meaning. As such, I'd
much rather it *didn't* write data anywhere,
because it's probably a bug. (And what do you
think of this one? UB again?)

strcpy(NULL, NULL)
Also I want my library code to be bullet-proof and NOT CAPABLE of
causing a crash (or nasal issuance). I do not consider it the
libraries domain to troubleshoot client code.

Aren't those two goals contradictory? If you want to bullet-proof
your library code, then you do need to check for NULLs and whatnot
(thus effectively "troubleshooting" whatever junk the client code
throws at you).

I prefer not to troubleshoot the client's code, either. I think
that's the client's job. If he passes NULL to something that
doesn't expect NULL (and he knows it), then he's being foolish
and can troubleshoot his own dang code. :)

[Probably different meanings for the word "troubleshoot."
I'm using it in the sense of "fix the errors post-facto,"
as distinct from "prevent" ("stop errors from happening")
or "ignore" ("ignore").]

My opinion, is that NULL is just one of zillions of invalid pointer
arguments and there's no point in treating it special.

I don't see how you can make strcpy, bulletproof.
If s1 isn't NULL and doesn't point to an object,
how can you tell from inside of strcpy?

char s1[] = "";
char s2[] = "";
strcpy(s1 + 1, s2);
 
D

Derk Gwen

# pete wrote:
#
# > Do you mean that you would like
# > strcpy(s1, NULL);
# > to have the exact same side effect as
# > *s1 = '\0';
#
# Yes.

You are, of course, free to define your own string copy on top of or instead of
the usual one.
 
C

CBFalconer

Programmer said:
Well,... I don't know if this helps or hurts your position, but
I agree with you, and my library code often treats a const char*
argument as "" if passed NULL.

My reasoning is simple: I can't AT ALL count on what happens if I
ignore a NULL value and use it. If I *could* my stance might change.

Also I want my library code to be bullet-proof and NOT CAPABLE of
causing a crash (or nasal issuance). I do not consider it the
libraries domain to troubleshoot client code.

Further, in many cases (at least in my code), a NULL char* pointer
has a "no string" semantic, and I consider that very close to an
empty string. Close enough to treat it thus in a "strlen" function
or "strcpy" function.

At last, an oasis of sanity :) However I disagree on strlen,
since it is often used to find the end of a string for
modification purposes. e.g.:

if ((i = strlen(s)) && ('\n' == s[i-1]))
s[i-1] = '\0';

although this particular sample would work with such a strlen.
Preferred would be:

if (s && (i = strlen(s)) && ('\n' == s[i-1]))
s[i-1] = '\0';
/* assert that s is NULL or is not terminated with \n */

A cpy function has no downside, as the output is converted into a
proper C string.
 
C

CBFalconer

Arthur J. O'Dwyer said:
.... snip ...

(And what do you think of this one? UB again?)

strcpy(NULL, NULL)

No, nobody has recommended that. That is not a const string.
 
M

Michel Bardiaux

Chris Torek wrote:
[snip]
Finally, and if my crystal ball is working again, the third common
problem is the one you are actually running into. If a comparison
function is not 100% consistent in deciding that, when a<b, b>a,
some qsort() variants will run wild. Hence this:

int bad_compare(const void *l, const void *r) {
return (rand() % 3) - 1;
}

is a terrible function to use, and causes real qsort()s to run off
into the weeds.

The above seems so stupid a mistake as to be impossible; however, a
subtle variation that I *have* seen (and not in my code!) is:

int bad_compare(const void *l, const void *r) {
int d=strcmp(l, r);
if(d) return d; else return -1;
}

Can, and did, cause qsort to crash, screw up, and blow nasal demons.
(This particular libc was O32 on SGI IRIX 6.2)
 
P

Programmer Dude

pete said:
My opinion, is that NULL is just one of zillions of invalid pointer
arguments and there's no point in treating it special.

IMO, it's a more (much more) common value than any random values.
Because of that--and because it is detectable--I choose to check
for it.
I don't see how you can make strcpy, bulletproof.
If s1 isn't NULL and doesn't point to an object,
how can you tell from inside of strcpy?

Obviously you can't. Nothing is foolproof. That doesn't mean you
don't do what you can (IMO). Again, my primary goal is to reduce,
as best as *possible*, runtime nasal issuance. The idea of helping
a developer (usually me) debug code during development is much less
important.
 
P

Programmer Dude

Derk said:
You are, of course, free to define your own string copy on top
of or instead of the usual one.

Of course, but just FYI, I believe this is more about creating
our own stringish functions. (But I tuned in late, so maybe not.)
 
P

Programmer Dude

CBFalconer said:
Further, in many cases (at least in my code), a NULL char* pointer
has a "no string" semantic, and I consider that very close to an
empty string. Close enough to treat it thus in a "strlen" function
or "strcpy" function.

At last, an oasis of sanity :) However I disagree on strlen,
since it is often used to find the end of a string for
modification purposes. e.g.:

if ((i = strlen(s)) && ('\n' == s[i-1]))
s[i-1] = '\0';

If s is NULL, aren't you going to have problems anyway, regardless
of what strlen() does?
Preferred would be:

if (s && (i = strlen(s)) && ('\n' == s[i-1]))
s[i-1] = '\0';
/* assert that s is NULL or is not terminated with \n */

That is probably how I'd write it.
A cpy function has no downside, as the output is converted into
a proper C string.

Agreed. Thing is, what are your options with a strlen() function?
It should return a size_t, so a negative return value isn't an
option to signal error, C has no exceptions, and zero is a valid
result. What really are your choices?

* You *do* deref the passed char* without checking
and whatever happens happens (not an option in my mind).

* You check the char* and detect NULL. Now what? Since the
first is (for me) not an option, I have to return *something*. I
can't think of any better value than 0. Case of least worst to me.
 
J

John L

Programmer Dude said:
Agreed. Thing is, what are your options with a strlen() function?
It should return a size_t, so a negative return value isn't an
option to signal error, C has no exceptions, and zero is a valid
result. What really are your choices?

* You *do* deref the passed char* without checking
and whatever happens happens (not an option in my mind).

* You check the char* and detect NULL. Now what? Since the
first is (for me) not an option, I have to return *something*. I
can't think of any better value than 0. Case of least worst to me.

What would happen if you returned -1 cast to size_t?
If the caller remembers to check ... but if not then
maybe that would be worse, I suppose.

John.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,077
Messages
2,570,568
Members
47,204
Latest member
abhinav72673

Latest Threads

Top