main() in C90

C

CBFalconer

jacob said:
Walter Roberson wrote:
.... snip ...


This is irrelevant. You mean that if the committee specified
the above limits foe asctime() C would "change its nature"

If you ever learn not to castigate anyone who disagrees with you,
you just might eventually find that your suggestions at least get
read. This is probably a futile suggestion.
 
R

Richard Heathfield

jacob navia said:
You can't read?

It isn't me who can't read. Look at Harald van Dijk's reply (parallel to
yours) for an example of how to disagree with people without being an
idiot about it.
 
R

Richard Heathfield

Harald van D?k said:
[asctime]
jacob navia said:
The behavior for out of range arguments is NOT SPECIFIED. They didn't
take the trouble of SAYING that years should be smaller than 10000, and
months/days should be smaller than 31.

The limits are easily deduced from 4.12.3.1 of C90 or 7.23.3.1 of C99.
For the buffer not to overflow:
tm_year must be in the range 0-8099.

This is *not* specified in 7.23.1. Additionally, I see no reason to
assume the valid values start at 0.

Oops, you're right - it could indeed be negative. So that would mean that
the range of values into which tm_year must fall to avoid buffer overflow
would appear to be -2899 to 8099, which gives you a slightly wider range.
I agree that it's not specified in 7.23.1, but I still maintain that it's
easily deduced. Okay, maybe not so easily that I didn't get it wrong on
this occasion! But nevertheless, after one round of QA we appear to have
arrived at the right answer.
How can mktime normalise a tm_year >8099 to <8099?

Another fair cop.

This is obvious.


This is obvious.


This is obvious.


This is non-obvious but explicit.

With asctime(), the problem is non-obvious and merely quietly suggested.

Sorry, but I must disagree here. We're talking about the C Standard
document itself. If you don't - er, sorry, let me re-word that: if one
does not read the document, one will not read any explicit warnings it
contains. And if one does read the document, or at least the asctime part
of it (which is far from long-winded), one will see a 26-byte buffer being
handed to sprintf in the code (asctime provides C code as an "as if" for
the algorithm to be used). That hard-coded buffer should be a bit of a
clue. Furthermore, the wording "The asctime function converts the [...]
time [...] into a string" should *immediately* ring bells in any C
programmer's head: "What string, where? How big? Who owns it? Do I have to
free it? Will I overwrite the previous value if I printf("%s-%s\n",
asctime(x), asctime(y))?" So even if one didn't happen to notice the
C-as-algorithm before, sure as eggs is eggs one will notice it when one
looks for the answers to those questions. So one *will* spot the limited
size of the array, and from that and the sprintf call it is trivial to
deduce the ranges that I did deduce (and not quite so trivial to spot that
you can actually extend the year range back a further not-quite-three
millennia).

Incidentally, I'm not sure why they didn't take the opportunity in C99 to
make it an snprintf call, but c'est la vie.
 
J

jacob navia

Richard said:
jacob navia said:


It isn't me who can't read. Look at Harald van Dijk's reply (parallel to
yours) for an example of how to disagree with people without being an
idiot about it.

Angry Your Majesty?

I am sorry but I do not care.

You argue that a user of the standard should
know how to avoid buffer overflows by carefully
avoiding any input to a badly designed software
by ensuring that the input doesn't exceed
unspecified limits.

GREAT!

And you agree with the committee that any error should be
rewarded with a buffer overflow ("corrupting memory" as they
call it), without any problems.

GREAT!
 
R

Richard Heathfield

[asctime]

jacob navia said:

You argue that a user of the standard should
know how to avoid buffer overflows
Right.

by carefully
avoiding any input to a badly designed software
by ensuring that the input doesn't exceed
unspecified limits.

The limits can be deduced from information published in the Standard.
And you agree with the committee that any error should be
rewarded with a buffer overflow ("corrupting memory" as they
call it), without any problems.

I agree with sensible programmers who ensure that the input they provide to
a standard library function is appropriate to that function. Writing a
validation wrapper for asctime is trivial. ISO C implementations provide
us with a considerable degree of expressive power with very little
overhead. If we wish to add a safety layer, that's our choice, and we have
the freedom *not* to do so in situations whose very nature renders the
safety layer unnecessary. There is a trade-off between safety and
performance. Whilst it is often wise to err on the side of safety, there
is no point in situations where safety is simply not an issue. For
example, let's say we're looping through every second in 2008, that's
31622400 iterations. Once we've got the code right in dev, it's right, and
it isn't going to break by magic. A paranoid asctime function would just
slow us down. At times where we do need the safety (e.g. working from
stream input), we can do our own range checks. It's not rocket science.
 
J

jacob navia

Richard said:
[asctime]

jacob navia said:

You argue that a user of the standard should
know how to avoid buffer overflows
Right.

by carefully
avoiding any input to a badly designed software
by ensuring that the input doesn't exceed
unspecified limits.

The limits can be deduced from information published in the Standard.
And you agree with the committee that any error should be
rewarded with a buffer overflow ("corrupting memory" as they
call it), without any problems.

I agree with sensible programmers who ensure that the input they provide to
a standard library function is appropriate to that function. Writing a
validation wrapper for asctime is trivial. ISO C implementations provide
us with a considerable degree of expressive power with very little
overhead. If we wish to add a safety layer, that's our choice, and we have
the freedom *not* to do so in situations whose very nature renders the
safety layer unnecessary. There is a trade-off between safety and
performance. Whilst it is often wise to err on the side of safety, there
is no point in situations where safety is simply not an issue. For
example, let's say we're looping through every second in 2008, that's
31622400 iterations. Once we've got the code right in dev, it's right, and
it isn't going to break by magic. A paranoid asctime function would just
slow us down. At times where we do need the safety (e.g. working from
stream input), we can do our own range checks. It's not rocket science.

The limits comparison is an integer comparison and a jump.

In most processors this is 2-3 instructions. Then, there is a
call to C99 printf, that is surely at least 3000 - 4000 instructions,
several function calls, and a quite BIG overhead.

But a simple error checking comparison of 2 instructions is too much for
you.


Your attitude towards errors and error checking is the same as
the committee. "Error checking is stupid. C doesn't do error checking".

I quote your message:

"If we wish to add a safety layer, that's our choice, and we have
the freedom *not* to do so in situations whose very nature renders the
safety layer unnecessary."

It is so easy to see that the ranges of the eyar that you got it
wrong in your first try.


This after I pointed to you of that error, after you
read the standard, etc.

A normal programmer will never discover that. I proposed that we
calculate the maximum size of that buffer instead of the
hardwired "26" that is the standard text.

Nope, they will not do it.

Mr Cleaver that proposed the change to replace overflowing
numbers with an asterisk was rejected too.

You defend them becasue you and they have the same basic
philosophy towards error checking:

"Error checking is unnecessary overhead"
 
I

Ioannis Vranos

jacob said:
You defend them becasue you and they have the same basic
philosophy towards error checking:

"Error checking is unnecessary overhead"


Off topic, but I think C++ is more suitable for you.
 
R

Richard Heathfield

jacob navia said:

The limits comparison is an integer comparison and a jump.

In most processors this is 2-3 instructions. Then, there is a
call to C99 printf, that is surely at least 3000 - 4000 instructions,
several function calls, and a quite BIG overhead.

Sure - but you don't necessarily need to call printf after asctime. C
certainly doesn't require this. You might have other plans for the string.
But it seems to me that you might be talking about the sprintf code laid
out in the Standard. If so, remember that it's an "as if" situation, and
it would not surprise me if library implementors have found much quicker
ways to do it, given that all the types concerned are integer types.
But a simple error checking comparison of 2 instructions is too much for
you.

Not at all. I'm saying that the programmer should have the *choice*.
Your attitude towards errors and error checking is the same as
the committee. "Error checking is stupid. C doesn't do error checking".

No, my attitude is that error checking is very sensible, and should be done
whenever appropriate. But sometimes the right place to decide whether
error checking is appropriate is *outside* the library function. I think
this is one of those situations.
I quote your message:

"If we wish to add a safety layer, that's our choice, and we have
the freedom *not* to do so in situations whose very nature renders the
safety layer unnecessary."

It is so easy to see that the ranges of the eyar that you got it
wrong in your first try.

Sure - but did you notice that my error was on the side of caution? The
range of values that asctime can represent without overrunning the buffer
is actually greater than I had claimed. I shouldn't have got it wrong but,
if I had done so in production code, the buffer would still have been safe
provided the values in the struct tm were within the ranges I'd
mis-specified.
This after I pointed to you of that error,

Wrong. My error was pointed out by Harald van Dijk.
after you read the standard, etc.

Yes, I overlooked the possibility that tm_year might be negative. This
makes the acceptable value range (from asctime's perspective) wider, not
narrower.
A normal programmer will never discover that.

The kind of programmer who reads the Standard carefully and attentively
will discover it when he or she needs to know it and looks it up. The kind
of programmer who does not read the Standard carefully and attentively
will never notice the omission of explicitly specified ranges anyway.
I proposed that we
calculate the maximum size of that buffer instead of the
hardwired "26" that is the standard text.

What is the maximum size of the buffer? A struct tm is packed to the
gunwales with ints, and ints have no maximum size in C.
Nope, they will not do it.

Mr Cleaver that proposed the change to replace overflowing
numbers with an asterisk was rejected too.

You defend them becasue you and they have the same basic
philosophy towards error checking:

"Error checking is unnecessary overhead"

But I do not have this philosophy. On the contrary, I think error checking
is very important, but I do think that the higher up the call chain it can
be done, the better. If I can use an analogy here, imagine a government
building, complete with security fence and gate guards. The guards check
your pass at the gate. Maybe the security guard in Reception will check
it, too. And then maybe you have to swipe it over an electronic lock
before you can get in. So far, so annoying, but we can see why it might be
necessary. But *once you're in*, imagine what it would be like if, every
time you met anyone else in the building, they checked your pass *again*.
And then you go to another office (check, check, check), and when you get
back to the first office they check it *again*. You'd hardly have time to
get anything done, because you'd spend most of your time showing your
pass. That level of security would be intrusive and counter-productive.

So you build a firewall around your core routines, and you check the data
at the firewall, and you only send data on to the core routines if you
know it's valid. To me, that's just plain common sense.
 
A

Antoninus Twink

If you ever learn not to castigate anyone who disagrees with you,
you just might eventually find that your suggestions at least get
read.

*splutter* My coffee just went everywhere!

Said without the slightest trace of irony, too! Perfect.
 
W

Walter Roberson

What's wrong with simply changing the behavior of asctime() by
replacing "sprintf(result," with "snprintf(result, sizeof(result)," in
7.23.3.1p2? That would seem to be sufficient to prevent the buffer
overrun.

Jacob specifically quoted the DR about "Corrupting memory" being
part of "the range of undefined behavior", and took exception to that.
That is a more general dissatisfaction than with the result of
the single library function asctime(). Fixing asctime() alone would
not fix the more general issue that as far as C is concerned,
corrupting memory is an acceptable part of the range of
"undefined behavior".

Your proposal is therefor just a band-aid over one particular wart;
removing the possibility that corrupting memory is permitted
behavior for "undefined behaviour" everywhere in the C standard would
require the sort of checks I outline, such as mandatory bounds checking
and run-time memory alignment checking for unions.
 
W

Walter Roberson

Yes. Years must be unsigned smaller than 10000
Month and days must be smaller than 99.
NOT VERY DIFFICULT!

Your complaint posted in what I replied to was not that one
particular library function could corrupt memory, but rather that
corrupted memory was an acceptable result of undefined behavior.
Patching one library function does not "improve C" to ban the
possibility of corrupted memory from undefined behavior.

Similarily, if you leave open the possibility in C that corrupted
memory is permitted to result from undefined behavior, then you have
lost any grounds for complaining that any particular library function
may corrupt memory when called with parameters out of range.


If you (for example) pass fscanf() a pointer to a float
in a location where the format specifier has been told to read
a double, then you will likely get corrupted memory. How would you
be satisfied that people had acted to "improve C" in the sense of your
"GREAT! And it stays that way because those people refuse to improve C."
if this possibility of fscanf() memory corruption is to be made
impossible? Depricate fscanf() and add in its place a new
text scanning routine that does run-time sizing or typing of its
arguments so that it cannot overwrite extra memory? Depricate fscanf()
and in its place add a series of scan_float() scan_double()
and so on that do not take pointers to the result and instead simply
output the scanned values with the programmer having to assign each value
individually? Adopt the C++ style << and >> I/O operators?
 
J

jameskuyper

Walter said:
Jacob specifically quoted the DR about "Corrupting memory" being
part of "the range of undefined behavior", and took exception to that.

I understood him as objecting to the fact that this was given as a
reason for the fact that committe ingnored the problem, not as a more
general complaint about undefined behavior. I thought he wanted
asctime() to have defined behavior. I didn't think he was expressing
opposition to the fact that undefined behavior includes the
possibility of corrupting memory. He might oppose it, but if so that
sentence didn't clearly express that opposition.
That is a more general dissatisfaction than with the result of
the single library function asctime(). Fixing asctime() alone would
not fix the more general issue that as far as C is concerned,
corrupting memory is an acceptable part of the range of
"undefined behavior".

Your proposal is therefor just a band-aid over one particular wart;
removing the possibility that corrupting memory is permitted
behavior for "undefined behaviour" everywhere in the C standard would
require the sort of checks I outline, such as mandatory bounds checking
and run-time memory alignment checking for unions.

As you said "These things could be done, but would the result still be
C?". If a future version of the C standard did actually mandate such
changes, the slow rate with which it would be adopted would make C99
look like an instant success, by comparison.

As far as C is concerned, a rewrite of asctime() to prevent overflow
is the right solution.
 
R

Richard Heathfield

(e-mail address removed) said:

As far as C is concerned, a rewrite of asctime() to prevent overflow
is the right solution.

Since overflowing a buffer necessarily invokes undefined behaviour,
implementations are free *right now* to protect asctime's buffer from
overflow if they wish, because an unoverflowed buffer is one legal outcome
of an overflowed buffer!
 
K

Kenny McCormack

*splutter* My coffee just went everywhere!

Said without the slightest trace of irony, too! Perfect.

CBF is, if nothing else, a master of the perfect delivery.
What style, what grace...!
 
J

jameskuyper

Richard said:
(e-mail address removed) said:



Since overflowing a buffer necessarily invokes undefined behaviour,
implementations are free *right now* to protect asctime's buffer from
overflow if they wish, because an unoverflowed buffer is one legal outcome
of an overflowed buffer!

Agreed - but it would be better if the standard mandated a specific
behavior, or at least mandated the absence of buffer overflow.
 
J

jacob navia

I understood him as objecting to the fact that this was given as a
reason for the fact that committe ingnored the problem, not as a more
general complaint about undefined behavior. I thought he wanted
asctime() to have defined behavior. I didn't think he was expressing
opposition to the fact that undefined behavior includes the
possibility of corrupting memory. He might oppose it, but if so that
sentence didn't clearly express that opposition.

I think that any SERIOUS specifications must treat error
handling correctly and specify for ALL the range of
possible inputs what the outcome of the function should be.

The rejected proposal of Mr Cleaver proposed that in case of
overflow the output should contain stars ('*') in the overflowed
positions. That is a sensible outcome that would transform
a nadly specified function with no error handling into a
correctly specified function for all possible inputs.

The cmmittee rejected that solution and left the behavior
UNSPECIFIED!
As you said "These things could be done, but would the result still be
C?". If a future version of the C standard did actually mandate such
changes, the slow rate with which it would be adopted would make C99
look like an instant success, by comparison.

As far as C is concerned, a rewrite of asctime() to prevent overflow
is the right solution.

Yes.

What is the philosophy behind

"C is so full of warts that fixing this one doesn't matter" ???

I think that fixing them all is the only possible solution and I press
this issue again and again because I want it fixed. I think C is
deliberately left in this sorry state so that C++ can shine even
better.

There is NO reason to specify in that way asctime(). It can be done
correctly without any problems!

o snprintf would solve that
o a few tests for wrong values would solve that.

Why leave it like that?
 
J

jacob navia

Walter said:
Similarily, if you leave open the possibility in C that corrupted
memory is permitted to result from undefined behavior, then you have
lost any grounds for complaining that any particular library function
may corrupt memory when called with parameters out of range.

WHAT IS THIS?

Since UB corrupts memory anyway, let's put UB in the C standard
so that anyone that reads it can laugh:

"Look at this C heads. They put a buffer overflow in their
standards document"
If you (for example) pass fscanf() a pointer to a float
in a location where the format specifier has been told to read
a double, then you will likely get corrupted memory.

That is why it is specified that you should pass a pointer
to a double and NOT a pointer to a float. In asctime() however
NO SPECIFICATION about maximum data ranges is done at ALL!

You are pushing this attitude towards errors to its ridiculous
extreme. Since C is fucked up anyway then let's leave the
buffer overflows there. Who cares.
 
J

jacob navia

Walter said:
Jacob specifically quoted the DR about "Corrupting memory" being
part of "the range of undefined behavior", and took exception to that.
That is a more general dissatisfaction than with the result of
the single library function asctime(). Fixing asctime() alone would
not fix the more general issue that as far as C is concerned,
corrupting memory is an acceptable part of the range of
"undefined behavior".

NO!

I want asctime(à fixed because it can be done VERY EASILY!!!
It suffices to specify correctly the size of the buffer OR
the allowed range of the arguments. That is not rocket science!

Of course I am not against eliminating all possible UB in all
possible programs, what are you talking about?

Your proposal is therefor just a band-aid over one particular wart;
removing the possibility that corrupting memory is permitted
behavior for "undefined behaviour" everywhere in the C standard would
require the sort of checks I outline, such as mandatory bounds checking
and run-time memory alignment checking for unions.

Look Mr, maybe removing THIS wart is not such a big deal but it would
be at least THIS WART GONE!

What is this philosophy?

"C is so fucked up that removing this wart wouldn't make any difference"
 

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,078
Latest member
MakersCBDBlood

Latest Threads

Top