Impossible question?

S

Seebs

Well it took over 200 posts to this newsgroup to explan the problems
with fgets(). Eventually the penny dropped, but even experienced
programmers like our FAQ maintainer were getting hot under the collar
and threatening to killfile. My conclusion is that most human
programmers aren't skilled enpugh to use fgets() safely and it takes
an unreasonably long time to train them to do so.

Huh?

You've stumped me. It's incredibly easy to use fgets() safely.

char buffer[80] = { '\0' };
fgets(buffer, 79, stdin);
Meanwhile gets() can be implemented safely, of course.

I don't see how this is possible.
Often it is
implemented with reasonable safety (safe except in the case of
malicious attack, which if the program is operating in an environment
where a C compiler is avialable, isn't a serious concern).

You say "often". This implies some sort of statistical information.

Please share with us how many implementations of gets() you've evaluated,
and in what way they have attained this "reasonable safety"? Please
also explain what you mean by "safe except in the case of malicious
attack".

I guess... Mostly, this just sounds like incredibly bad software design.
"Safe except in the case of malicious attack" is pretty pointless, since
a whole lot of software gets attacked. I also don't have any idea
what you mean by "if the program is operating in an environment where
a C compiler is available, isn't a serious concern."

Consider basically any Unix-like system. It will typically have a C
compiler available, and be running software which was written on C on
network ports. That is to say, it will be FULL of examples of software
written in C, operating in an environment where a C compiler is available,
and which could reasonably be an attack vector.

I feel like I'm listening to someone pointing out that it's ridiculous
to have your brakes checked because most of the time cars are used on level
surfaces, where brake failure isn't a serious concern.

-s
 
B

Ben Bacarisse

Malcolm McLean said:
Well it took over 200 posts to this newsgroup to explan the problems
with fgets(). Eventually the penny dropped, but even experienced
programmers like our FAQ maintainer were getting hot under the collar
and threatening to killfile. My conclusion is that most human
programmers aren't skilled enpugh to use fgets() safely and it takes
an unreasonably long time to train them to do so.

Meanwhile gets() can be implemented safely, of course. Often it is
implemented with reasonable safety (safe except in the case of
malicious attack, which if the program is operating in an environment
where a C compiler is avialable, isn't a serious concern).

It seems as if you are trying to fog the issue with a subtle choice of
words and a shift in meaning from one function to the other. Is
"implemented safely" the same a "use safely"?

It takes seconds to train people to use fgets in such a way that it does
not overrun the buffer. It is almost impossible to do that with gets.

Anyone not familiar with the particular bees you have in your bonnet
might get the idea that gets is preferable to fgets (from the point of
view of safety). By all means grind away this axe some more, but please
try to word it in a way that won't lead inexperienced programmer astray.
 
S

Seebs

Consider an implementation with fat pointers, in C terms

This is an interesting point. Theoretically, you could have a C
implementation in which gets could be implemented safely.
Now gets() can be implemented so that it always issues a diagnostic
error message and terminates the program on buffer overflow. Given
that the programmer doesn't know how to handle long inputs, this is
both safe and the safest thing it can do.

It is not at all obvious that it is "safe", though it may be "the safest
thing it can do". It is quite easy to find examples of programs which,
if they terminate, result in people dying.

-s
 
K

Keith Thompson

Malcolm McLean said:
Consider an implementation with fat pointers, in C terms

struct fat
{
void *ptr;
void *start;
void *end;
}

every attempt to modify the ptr member is checked to make sure it
doesn't go past end.

Now gets() can be implemented so that it always issues a diagnostic
error message and terminates the program on buffer overflow. Given
that the programmer doesn't know how to handle long inputs, this is
both safe and the safest thing it can do.

And every pointer operation in every C program pays the price in
performance.

Or you could just not use gets(), since it cannot be implemented
safely without drastic modifications to the compiler.

Do you use gets() yourself? Why are you defending it?
 
W

Willem

Keith Thompson wrote:
<snip ... fat pointers ...>
)> Now gets() can be implemented so that it always issues a diagnostic
)> error message and terminates the program on buffer overflow. Given
)> that the programmer doesn't know how to handle long inputs, this is
)> both safe and the safest thing it can do.
)
) And every pointer operation in every C program pays the price in
) performance.

Irrelevant.

) Or you could just not use gets(), since it cannot be implemented
) safely without drastic modifications to the compiler.

Irrelevant.

) Do you use gets() yourself? Why are you defending it?

He's not defending it.
He is just pedantically attacking the absolute statement that
"the C standard does not permit a safe implementation of gets()".

The C standard does *permit* a safe implementation. It just doesn't
make it easy or desirable. Rather the opposite. But it doesn't outright
prohibit it. Which is the (quite pedantic) point he was making.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
B

Ben Bacarisse

Seebs said:
Huh?

You've stumped me.

Imagine how any beginners feel! He's switching meanings of "safe"
between gets and fgets.
It's incredibly easy to use fgets() safely.

char buffer[80] = { '\0' };
fgets(buffer, 79, stdin);

[Aside: that's belt-and-braces safe. fgets takes the buffer size
(despite expecting an int) and knows what to so -- you can pass 80 or
sizeof buffer here quite safely.]

In Malcolm's view, that's unsafe because it could read a partial line.
Because (in his view) it is virtually impossible to get people to check
for a partial line, fgets is unsafe because of what the program might do
if it assumed a whole line had been read.

This, of course, is an easy problem to solve.
I don't see how this is possible.

....via the almost mythical fat pointers. Of course, vanishing few
people have access to such a gets but that, again, is just an annoying
detail. But note: safety is now being applied to the implementation of
the function and not its use.

Any use of such a gets function will also have problems since over-long
lines can still cause some unexpected program behaviour and that's not
an easy problem to solve.

I hope I have not muddied the water by paraphrasing Malcolm's point of
view, but the previous trip round this loop seems fresh in my memory so
I thought I'd try to speed things up.

<snip>
 
B

BartC

Malcolm McLean said:
Consider an implementation with fat pointers, in C terms

struct fat
{
void *ptr;
void *start;
void *end;
}

every attempt to modify the ptr member is checked to make sure it
doesn't go past end.

If the fat pointer only contains the limits of an allocated memory block,
overflow can still occur from one part of a block to another.

For example if you only want to use the first 128 bytes of a 1024-byte
block, with the 129th byte onwards containing critical data.

If the fat pointer can contain arbitrary limits, then it looks like a lot
more programming effort than just using fgets:

gets(createfatptr(buffer,&buffer[0],&buffer[127]));
 
K

Keith Thompson

Willem said:
Keith Thompson wrote:
<snip ... fat pointers ...>
)> Now gets() can be implemented so that it always issues a diagnostic
)> error message and terminates the program on buffer overflow. Given
)> that the programmer doesn't know how to handle long inputs, this is
)> both safe and the safest thing it can do.
)
) And every pointer operation in every C program pays the price in
) performance.

Irrelevant.

) Or you could just not use gets(), since it cannot be implemented
) safely without drastic modifications to the compiler.

Irrelevant.

) Do you use gets() yourself? Why are you defending it?

He's not defending it.
He is just pedantically attacking the absolute statement that
"the C standard does not permit a safe implementation of gets()".

The C standard does *permit* a safe implementation. It just doesn't
make it easy or desirable. Rather the opposite. But it doesn't outright
prohibit it. Which is the (quite pedantic) point he was making.

Ok.

It's not possible to implement gets() safely *without radical
changes to the compiler*. It's not possible to write a standard C,
or even non-standard C, implementation of gets() that can be used
safely with an arbitrary compiler in an environment where you don't
control what appears on stdin. The safety he proposes is not in
the implementation of gets(), it's in the compiler.

It also depends on the compiler generating code that always computes the
bounds for fat pointers correctly. I'm not convinced that's always possible.
 
K

Keith Thompson

Keith Thompson said:
It's not possible to implement gets() safely *without radical
changes to the compiler*.
[...]

Or, to be more precise, without radical assumptions about the
behavior of the compiler. In particular, it requires assuming safe
behavior for certain constructs whose behavior is not defined by
the C standard.

The behavior of this program:

#include <stdio.h>
int main(void) {
char buf[10];
gets(buf);
return 0;
}

is not defined by the C standard if the first line of input on stdin
is, say, 20 characters long. An implementation can do things that
avoid certain kinds of bad behavior, but it cannot change the fact
that the behavior is undefined by the standard.

Even given a hypothetical fat-pointer implementation that does
complete and correct bounds checking, the program's behavior is
likely to be "safe" only in the sense that it terminates rather than
stepping on random memory. Or gets() could return a null pointer
to indicate an error -- but does it then read and discard the rest
of the input line?
 
S

Seebs

Seebs said:
It's incredibly easy to use fgets() safely.

char buffer[80] = { '\0' };
fgets(buffer, 79, stdin);
[Aside: that's belt-and-braces safe. fgets takes the buffer size
(despite expecting an int) and knows what to so -- you can pass 80 or
sizeof buffer here quite safely.]

Ahh, yes, I missed the text "one less than the..." in the description I
was reading.

Interestingly, it says:

If any characters are read and there
is no error, a `\0' character is appended to end the string.

This implies that, in the event of an error, there may be no trailing '\0'.
So maybe I do need that extra sanity-check.
In Malcolm's view, that's unsafe because it could read a partial line.
Because (in his view) it is virtually impossible to get people to check
for a partial line, fgets is unsafe because of what the program might do
if it assumed a whole line had been read.

I guess I would be a lot less concerned about "possibly confused" than I
would about "rooted".

-s
 
W

Willem

Seebs wrote:
) Interestingly, it says:
)
) If any characters are read and there
) is no error, a `\0' character is appended to end the string.
)
) This implies that, in the event of an error, there may be no trailing '\0'.
) So maybe I do need that extra sanity-check.

Or, of course, you check the return value.

And according to the spec (pedantically speaking) fgets is allowed to
mangle your bugger anyway in case of an error, so checking the return
value is the safest anyway.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
N

Nick

Willem said:
Seebs wrote:
) Interestingly, it says:
)
) If any characters are read and there
) is no error, a `\0' character is appended to end the string.
)
) This implies that, in the event of an error, there may be no trailing '\0'.
) So maybe I do need that extra sanity-check.

Or, of course, you check the return value.

And according to the spec (pedantically speaking) fgets is allowed to
mangle your bugger anyway in case of an error, so checking the return
value is the safest anyway.

You know, I can cope with having my disk formatted;I can cope with the
nasal daemons; but please don't come round and mangle my bugger.
 

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,083
Messages
2,570,589
Members
47,211
Latest member
JaydenBail

Latest Threads

Top