gets() rationale

  • Thread starter Christopher Benson-Manica
  • Start date
S

Shuo Xiang

Greetings:

gets() exists for the same reason as the standard streams handling
functions such as printf() and scanf() -- it simply makes your program
look more cleaner and concise.

The standard streams are holy, their names are NOT to be casually
mentioned in the context of a C program, just as the Catholics do not
say the name of God -- Jehovah, casually ;-)

fgets() still has its own share of problems, beside the complicated
setup, for example, how do you make sure that you have gotten
everything the user put it? I think the most fool-proof way would be
to make a character-based finite-state-machine that reacts to each one
of the user's keystrokes in a specific manner. Much like an arcade
machine that senses the subtlest of the user movements. But then
that's overboard for Standard C and toy programs.

Regards,

Shuo Xiang
 
C

CBFalconer

Shuo said:
gets() exists for the same reason as the standard streams handling
functions such as printf() and scanf() -- it simply makes your
program look more cleaner and concise.

No it doesn't. It makes you look sloppy and ignorant. Read the
faq. And, in future, please DO NOT top-post. Your answer goes
after the material to which you are replying, after you have
deleted anything irrelevant to your reply. Top-posting after
being advised against it not only makes you look sloppy and
ignorant, it also marks you as rude.
 
K

Kelsey Bjarnason

No it doesn't.

Actually, it does:

char buff[128];
gets(buff);

vs

char buff[128];
fgets( buff, sizeof(buff),stdin);

The former is, indeed, cleaner and more concise.
It makes you look sloppy and ignorant.

However, it also has that effect. The two aren't exclusive. :)
 
C

CBFalconer

Kelsey said:
No it doesn't.

Actually, it does:

char buff[128];
gets(buff);

vs

char buff[128];
fgets( buff, sizeof(buff),stdin);

The former is, indeed, cleaner and more concise.

Oh very well, with the following proviso :)
However, it also has that effect. The two aren't exclusive. :)

Oh for orthagonality :) Which is why I recommend:

char * buf;
int err;
....
while (0 == (err = ggets(&buf))) {
/* do things with buf */
free(buf);
}

which can also be dumbed down to:

char * buf;
ggets(&buf);

with safety. See <http://cbfalconer.home.att.net/download/> My
philosophy for ggets was to preserve the utter simplicity of gets
without the penalty.
 
E

Eric

Kelsey Bjarnason said:
However, it also has that effect. The two aren't exclusive. :)

Nonsense.

There are perfectly legitimate uses for gets that would do nothing of
the sort. Although, those cases would always (as near as I can
determine) imply that buffer overflow would not be an troublesome issue.
 
K

Keith Thompson

Nonsense.

There are perfectly legitimate uses for gets that would do nothing of
the sort. Although, those cases would always (as near as I can
determine) imply that buffer overflow would not be an troublesome issue.

gets() can be used safely *only* if you have absolute control over
what the program will see on stdin. In typical environments, this
requires guaranteeing that the program using gets() cannot be invoked
directly by a user.

Even in such a context, fets() would serve the same purpose at the
expense of perhaps a tiny amount of extra code (passing two extra
arguments and allowing for the newline character that fgets() leaves
in the buffer). Personally, that's a price I will gladly pay rather
than having to prove, both to myself and to anyone who might read or
maintain the code, that a particular usage of gets() is actually safe.

I've never heard of an actual case of gets() being used safely in this
mannger, but I've seen numerous cases of it being used unsafely. (If
I recall correctly, the 1988 Morris Worm exploited one such unsafe
usage.)

The results of a buffer overflow, if you fail to prevent it, can vary
depending on the nature of the program in which it occurs. If it's in
something that has special privileges (e.g., in Unix terms, a daemon
running as root), the results can be almost arbitrarily bad. If it's
in a small unprivileged program whose failure won't cause any real
harm, it's not so bad -- but it still makes the programmer look
"sloppy and ignorant".
 
E

Eric

Keith Thompson said:
gets() can be used safely *only* if you have absolute control over
what the program will see on stdin. In typical environments, this
requires guaranteeing that the program using gets() cannot be invoked
directly by a user.

Even in such a context, fets() would serve the same purpose at the
expense of perhaps a tiny amount of extra code (passing two extra
arguments and allowing for the newline character that fgets() leaves
in the buffer). Personally, that's a price I will gladly pay rather
than having to prove, both to myself and to anyone who might read or
maintain the code, that a particular usage of gets() is actually safe.

Unless, of course, you don't have those extra bytes to spare that an
implementation of fgets() would need which gets does not.

In which case, you would be deemed a hero, by your boss, for getting
something to work which someone who had an irrational and absolute
hatred of gets() could not.

Would you really tell your boss that 'it can't be done' simply because
you would not use gets() and therefore be labeled sloppy and ignorant by
certain members of comp.lang.c?
 
B

Ben Pfaff

Unless, of course, you don't have those extra bytes to spare that an
implementation of fgets() would need which gets does not.

In which case, you would be deemed a hero, by your boss, for getting
something to work which someone who had an irrational and absolute
hatred of gets() could not.

A better solution would be to write a function that does not
store a trailing new-line, but does take a buffer length.
 
E

Eric

Ben Pfaff said:
A better solution would be to write a function that does not
store a trailing new-line, but does take a buffer length.

Unless, again, you don't have even the tiny bit of space for such a
thing. (hint: you will need some code to check the buffer length)

Whether you are willing to accept it or not, there simply do exist cases
where there is very little room to play around in and each and every bit
is important and cannot be wasted unnecessarily.
 
B

Ben Pfaff

Unless, again, you don't have even the tiny bit of space for such a
thing. (hint: you will need some code to check the buffer length)

Drop gets() and fgets() from the library on your device and you
will have plenty of room. Since your device is so small, there
is almost certainly a way to do that.
 
C

Chris Torek

I've never heard of an actual case of gets() being used safely in this
manner, but I've seen numerous cases of it being used unsafely. (If
I recall correctly, the 1988 Morris Worm exploited one such unsafe
usage.)

Yes. The Morris Worm had two primary methods of ingress. One used
a security hole in sendmail -- the hole itself was actually a
deliberate option, although its being enabled on virtually every
machine running sendmail was not, and the less said about this the
better :) (though I have no personal stake in it) -- and the other
used the fact that the finger daemon had:

char buf[512];
...
gets(buf);

in it, with a 512-byte "buf". (The program's stdin was, at this
point, connected to the network "finger" port, TCP port 79.)

This was perhaps the first remote buffer-overflow exploit, and
certainly the first really major one. The lesson it taught has
been learned over and over by (I believe) hundreds of millions of
(mostly Microsoft) users, but apparently not by server-writers. :)

(The University of Maryland's CS department, where I worked at the
time, managed to fend off the worm, in part because I had replaced
the finger daemon. Mine even logged the overflow attempts -- Pete
Cottrell got on the local TV news with a screen shot of finger log
file entries. [I was in Berkeley at the time.] The other part
was because Steve Miller had done a lot of sendmail work, closing
the hole.)
 
C

CBFalconer

Eric said:
Unless, of course, you don't have those extra bytes to spare that an
implementation of fgets() would need which gets does not.

In which case, you would be deemed a hero, by your boss, for getting
something to work which someone who had an irrational and absolute
hatred of gets() could not.

Would you really tell your boss that 'it can't be done' simply because
you would not use gets() and therefore be labeled sloppy and ignorant
by certain members of comp.lang.c?

No, I would write something like the following, and cackle:

#include stdio.h
#define MAXLGH 123

void inputline(char * buf)
{
int i = 0;
int ch;

while (EOF != (ch = getchar())) {
if ('\n' == ch) break;
if (i < MAXLGH-1) buf[i++] = ch;
}
buf = '\0';
}

and encourage the users to declare char arrays of size MAXLGH. I
could also be persuaded to return some status information rather
than the void.
 
E

Eric

Ben Pfaff said:
Drop gets() and fgets() from the library on your device and you
will have plenty of room. Since your device is so small, there
is almost certainly a way to do that.

Unless, of course, that has already been done.
 
E

Eric

CBFalconer said:
Eric said:
Unless, of course, you don't have those extra bytes to spare that an
implementation of fgets() would need which gets does not.

In which case, you would be deemed a hero, by your boss, for getting
something to work which someone who had an irrational and absolute
hatred of gets() could not.

Would you really tell your boss that 'it can't be done' simply because
you would not use gets() and therefore be labeled sloppy and ignorant
by certain members of comp.lang.c?

No, I would write something like the following, and cackle:

#include stdio.h
#define MAXLGH 123

void inputline(char * buf)
{
int i = 0;
int ch;

while (EOF != (ch = getchar())) {
if ('\n' == ch) break;
if (i < MAXLGH-1) buf[i++] = ch;
}
buf = '\0';
}

and encourage the users to declare char arrays of size MAXLGH. I
could also be persuaded to return some status information rather
than the void.


'The check of the buffer length put you over pre-defined limits. We're
going with another person who understands our situation. You're fired.'
 
M

Mark McIntyre

On Fri, 12 Dec 2003 17:45:17 -0500, in comp.lang.c ,
Would you really tell your boss that 'it can't be done' simply because
you would not use gets()

I'd tell him that I could do it, but only at the expense of
introducing a known and serious bug into the code which provided a
real risk of the programme crashing under perfectly normal conditions.
If he still wanted to do it, then I'd put it in writing, do it, and
send my resume out.
and therefore be labeled sloppy and ignorant by
certain members of comp.lang.c?

I can think of worse things to be called. The sort of programmer who
uses gets and crashes the air traffic control system of Chicago
Airport for example.
 
E

Eric

Ben Pfaff said:
Then how are you going to use gets(), as in your suggestion?

Why are you going to insist on putting in an absolutely unnecessary
buffer check in the subset of cases I am talking about, making the
problem unsolvable?
 
E

Eric

Mark McIntyre said:
On Fri, 12 Dec 2003 17:45:17 -0500, in comp.lang.c ,


I'd tell him that I could do it, but only at the expense of
introducing a known and serious bug into the code which provided a
real risk of the programme crashing under perfectly normal conditions.

So, you disagree with Keith Thompson who stated:

'gets() can be used safely *only* if you have absolute
control over what the program will see on stdin.'

?

You believe there absolutely does not exist any case where gets() can be
used safely?
 
M

Mark McIntyre

On 12 Dec 2003 15:45:55 -0800, in comp.lang.c , Ben Pfaff

Ben,

_____________________
/| /| | |
||__|| | Please do not |
/ O O\__ | feed the |
/ \ | Trolls |
/ \ \|_____________________|
/ _ \ \ ||
/ |\____\ \ ||
/ | | | |\____/ ||
/ \|_|_|/ | _||
/ / \ |____| ||
/ | | | --|
| | | |____ --|
* _ | |_|_|_| | \-/
*-- _--\ _ \ | ||
/ _ \\ | / `
* / \_ /- | | |
* ___ c_c_c_C/ \C_c_c_c____________
 
A

Arthur J. O'Dwyer

Unless, again, you don't have even the tiny bit of space for such a
thing. (hint: you will need some code to check the buffer length)

Whether you are willing to accept it or not, there simply do exist cases
where there is very little room to play around in and each and every bit
is important and cannot be wasted unnecessarily.

Now, I may be naive, but it seems to me that it is in those
situations where absolutely every byte in your program space is
significant that you would want to take the *most* care not to
stomp on any of those bytes.
One reason Windows can get away with so many loopholes and
overruns is because it bloats out over the entire RAM, so that
only a few overruns actually hit anything mission-critical (cf.
Core Wars). On a machine with very little RAM, presumably all your
mission-critical stuff is packed real close together, and a buffer
overrun of only two or three bytes could be absolutely disastrous.
In such a case, a competent programmer would certainly want to
protect his code! He'd use a format-checking input function like
scanf() or fgets(), not a RAM-stomping free-for-all like gets().

-Arthur
 

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
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top