gets() is dead

R

Richard Heathfield

(e-mail address removed) said:
I wouldn't say it's good news. Firstly, it will break a lot of old
code if it's dropped.

No, it won't break any old code that was not already broken.
Secondly, gets() is completely safe *as long as
_you_ control the data passed to it*.

And you can't guarantee that you do.
 
F

Flash Gordon

I wouldn't say it's good news.

I and many others here disagree.
> Firstly, it will break a lot of old
code if it's dropped.

Most people here (even those who have argued for keeping gets) think
that it is only useful for quick throw-away programs (which are not a
problem as they are going to be thrown away anyway) and very specialised
situations (which being very specialised do not occur often and so do
not make up a lot of code). Any other code needs to be fixed anyway, so
the sooner it will not build the better since it will force it to be
fixed or discarded.
> Secondly, gets() is completely safe *as long as
_you_ control the data passed to it*.

In such a situation you know the size of the buffer you have allocated
so is it really such a big problem to do:
fgets(buffer,sizeof buffer,stdin);
or
fgets(buffer,BUFFER_SIZE,stdin);

You could even write a macro
#define GETS(buffer) fgets(buffer,sizeof buffer,stdin)
which would be suitable for most usage.
> Of course it should never be
used in production code, but for private/development/toy code I find
it extremely useful.

See above for easy ways to live without it. If the buffer is not large
enough you are likely to find it easier to debug since the results will
be more predictable, if it is large enough it just means you have to
deal with the newline left in the buffer. So you could do:
#define GETS(buffer) ((fgets(buffer,sizeof buffer,stdin)!=NULL)? \
(buffer[strcspn(buffer,"\n")]=0,buffer):NULL)

Obviously you do not pass a pointer to this macro. It can be used as in:
#include <stdio.h>
#include <string.h>

#define GETS(buffer) ((fgets(buffer,sizeof buffer,stdin)!=NULL)? \
(buffer[strcspn(buffer,"\n")]=0,buffer):NULL)

int main(void)
{
char buf[10];
GETS(buf);
printf("'%s'\n",buf);
GETS(buf);
printf("'%s'\n",buf);
return 0;
}

markg@brenda:~$ gcc -ansi -pedantic -Wall -Wextra -O t.c
markg@brenda:~$ ./a.out

''

''
markg@brenda:~$ ./a.out
1
'1'

''
markg@brenda:~$ ./a.out
12345678
'12345678'

''
markg@brenda:~$ ./a.out
123456789
'123456789'
''
markg@brenda:~$ ./a.out
1234567890
'123456789'
'0'
markg@brenda:~$

Easily good enough for a throwaway program wanting gets type
functionality. I will even hereby grant everyone the permission to use
the code illustrated herein for any code of there own for any purpose
under any license with one exception. If you are publishing my idea
outside Usenet then you need my permission and inside Usenet you need to
acknowledge it as mine unless you can find prior art.
 
F

Flash Gordon

Eric Sosman wrote, On 26/04/07 18:17:

reality? It says that "gets has been declared an obsolescent
feature and deprecated." Do you have a reason to believe

I think it would be nice if the standard mandated emitting a diagnostic
for the use of any feature declared in the standard as obsolescent
and/or deprecated. Note that I am NOT saying it should fail to
compile/link, just that a diagnostic should be issued.
 
R

Richard Heathfield

Flash Gordon said:

I will even hereby grant everyone the permission to use
the code illustrated herein for any code of there own for any purpose
under any license with one exception. If you are publishing my idea
outside Usenet then you need my permission and inside Usenet you need
to acknowledge it as mine unless you can find prior art.

Very generous, Flash, but if it's all the same to you, I'll pass. :)
 
F

Flash Gordon

Richard Heathfield wrote, On 26/04/07 18:53:
Flash Gordon said:



Very generous, Flash, but if it's all the same to you, I'll pass. :)

I'm sure you have a suitable routine for situations where other might
consider using gets anyway :)

I would also not be surprised if something similar has been posted in
the past.
 
D

Dave Vandervies

Eric Sosman wrote, On 26/04/07 18:17:



I think it would be nice if the standard mandated emitting a diagnostic
for the use of any feature declared in the standard as obsolescent
and/or deprecated. Note that I am NOT saying it should fail to
compile/link, just that a diagnostic should be issued.

The standard makes no distinction between a diagnostic that causes
translation to be aborted and one that allows it to continue. Many
implementations make this distinction between "warnings" and "errors";
when invoked in conforming mode, such an implementation may issue either
a "warning" or an "error" for a syntax error or constraint violation
(and most do some of each), but only a "warning" for diagnostics not
required by the standard.

I don't think that getting required non-fatal warnings for obsolescent
or deprecated features would be worth creating that distinction in the
language implementation, especially since most reasonable implementations
already *do* issue non-fatal warnings for them.


dave
 
D

Dave Vandervies

Dave Vandervies said:
I don't think that getting required non-fatal warnings for obsolescent
or deprecated features would be worth creating that distinction in the
language implementation, especially since most reasonable implementations ^^^^^^^^^^^^^^
already *do* issue non-fatal warnings for them.

I meant "in the language specification", of course.

But even in this correction it took me three tries to convince my fingers
of that for some reason.


dave
 
D

Default User

Richard said:
Malcolm McLean said:



Oh dear. I sure hope I'm a counter-example, because otherwise I've
been using fgets() unsafely for years.

As he humbly discards the possibility that he's one of the best
programmers.




Brian
 
D

Dave Vandervies

As he humbly discards the possibility that he's one of the best
programmers.

I can't speak for him, but I suspect his response to that would be
similar to mine:

I like to think I'm good. If I tried hard enough, I could probably even
dig up supporting evidence for above average. But if I'm "one of the
best", we're all in trouble.

And I, too, have apparently been using fgets unsafely for years.


dave
 
M

Malcolm McLean

Chris Dollin said:
I think that's absurd. Do you have a reason for this interesting point of
view?
You've provided your own evidence.
You can't articulate why fgets() is dangerous, or why it could be considered
dangerous if you persist in disagreeing with me. A threat you can't
recognise is much more deadly than one that you can.
 
C

Charlton Wilbur

DU> As he humbly discards the possibility that he's one of the
DU> best programmers.

In my case, I have to. I know how inexpert I am, and the notion that
I might be one of the best is truly horrifying.

Charlton
 
G

Guest

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


No, it won't break any old code that was not already broken.


And you can't guarantee that you do.

You can if your code isn't strictly conforming ANSI C, you've forked a
process, and you're using pipes for communication between the parent
and the child.

Of course, if the only possible safe uses of gets() rely on extensions
to standard C, it wouldn't be bad to make gets() itself an extension
as well, so I'm not saying deprecating it was a bad idea.
 
F

Flash Gordon

Malcolm McLean wrote, On 26/04/07 20:58:
You've provided your own evidence.
You can't articulate why fgets() is dangerous, or why it could be
considered dangerous if you persist in disagreeing with me. A threat you
can't recognise is much more deadly than one that you can.

So tell us all why fgets is so dangerous that only the best programmers
can use it safely, especially as you came up with this in response to
discussion of gets being deprecated and the justification being
applicable to the unqualified %s in a scanf call.
 
K

Keith Thompson

Malcolm McLean said:
You've provided your own evidence.
You can't articulate why fgets() is dangerous, or why it could be
considered dangerous if you persist in disagreeing with me. A threat
you can't recognise is much more deadly than one that you can.

You haven't provided a reason for your claim, you've merely reiterated
it and implicitly insulted anyone who doesn't already agree with you.

I persist in disagreeing with you. Don't waste my time telling me
again that you're right and I'm wrong. Explain yourself.
 
F

Flash Gordon

Dave Vandervies wrote, On 26/04/07 20:08:
I meant "in the language specification", of course.

But even in this correction it took me three tries to convince my fingers
of that for some reason.

I don't think it would be a big thing, just adding one sentence (or
paragraph at the most). It is not as if it would be that big a thing for
most implementations to implement, after all most can warn against the
things which have been deprecated anyway.
 
M

Malcolm McLean

Keith Thompson said:
You haven't provided a reason for your claim, you've merely reiterated
it and implicitly insulted anyone who doesn't already agree with you.

I persist in disagreeing with you. Don't waste my time telling me
again that you're right and I'm wrong. Explain yourself.
OK.
No one else can articulate why fgets() is dangerous. Therefore there are two
possibilities. The first is that it isn't dangerous at all, the second is
that it is especially dangerous and even experienced programmers often can't
see the problem.

Why do I go for the second? Because there are two actions you need to take
when using fgets() safely.
Firstly you need to check for the trailing newline to be sure that the whole
line has been read. Secondly you need to take action in the event of a
failure to ensure that the partially read input doesn't cause any problems.
In practise these steps are seldom followed. The degree of danger obviously
depends on the application, whether it is possible for the input to be
sabotaged by some malicious person with access to the source. But it is
certainly there.
 
I

Ian Collins

Malcolm said:
OK.
No one else can articulate why fgets() is dangerous. Therefore there are
two possibilities. The first is that it isn't dangerous at all, the
second is that it is especially dangerous and even experienced
programmers often can't see the problem.

Why do I go for the second? Because there are two actions you need to
take when using fgets() safely.
Firstly you need to check for the trailing newline to be sure that the
whole line has been read. Secondly you need to take action in the event
of a failure to ensure that the partially read input doesn't cause any
problems.

Yes, but with fgets() you *can* check. With gets() or %s in scanf(),
you can't defend against malicious attack. The former is sloppy
practice, the latter a defect in the language.
 
F

Flash Gordon

Malcolm McLean wrote, On 26/04/07 22:07:
OK.
No one else can articulate why fgets() is dangerous. Therefore there are
two possibilities. The first is that it isn't dangerous at all, the
second is that it is especially dangerous and even experienced
programmers often can't see the problem.

Why do I go for the second? Because there are two actions you need to
take when using fgets() safely.
Firstly you need to check for the trailing newline to be sure that the
whole line has been read.

Anyone who either thinks about it or reads the specification for fgets
will know they need to check to see if a complete line has been read.
> Secondly you need to take action in the event
of a failure to ensure that the partially read input doesn't cause any
problems.

Anyone with any decent training in SW development will know they need to
define what action should be taken in the event of incorrect input and
write the SW to do this.
In practise these steps are seldom followed.

A lot of SW is written by people who are not very good.
> The degree of danger
obviously depends on the application, whether it is possible for the
input to be sabotaged by some malicious person with access to the
source. But it is certainly there.

That can be said about the input functions of any language.

If you have to specify the size of the line buffer then you have to deal
with the potential for a longer line being entered and handle it
correctly. If the language provides a function that will grow the buffer
until it is large enough then you have to allow for the possibility that
a line is too long for your available memory (I can easily construct a
file with a line too long for a machine with 32 bit addressing to load
in to its address space).

I'm interfacing to SW written in Java that crashes if given bad input.
With an earlier version of the SW we found that if we had 4 processes
sending data to this multi-user server code written in Java that we
would actually bring down the entire system, and this was without even
being malicious! The code doing the sending was also written in Java, BTW.
 
K

Keith Thompson

Malcolm McLean said:
OK.
No one else can articulate why fgets() is dangerous. Therefore there
are two possibilities. The first is that it isn't dangerous at all,
the second is that it is especially dangerous and even experienced
programmers often can't see the problem.

There is a third possibility, that you're wrong and the rest of us are
right.

As I already acknowledged, fgets() can be problematic, but it's not
nearly as bad as gets() or scanf("%s", ...).
Why do I go for the second? Because there are two actions you need to
take when using fgets() safely.
Firstly you need to check for the trailing newline to be sure that the
whole line has been read. Secondly you need to take action in the
event of a failure to ensure that the partially read input doesn't
cause any problems.

And the likely result of failing to do this is that a long line is
treated as if it were two or more shorter lines. It won't cause
undefined behavior.
In practise these steps are seldom followed. The degree of danger
obviously depends on the application, whether it is possible for the
input to be sabotaged by some malicious person with access to the
source. But it is certainly there.

fgets() *can* be used safely, and most of us here know how to do so.
Even if its limitations are ignored, the consequences are relatively
mild.
 
C

Christopher Benson-Manica

Malcolm McLean said:
No one else can articulate why fgets() is dangerous. Therefore there are two
possibilities. The first is that it isn't dangerous at all, the second is
that it is especially dangerous and even experienced programmers often can't
see the problem.

What do you advocate instead? fgetc()? (If you're arguing that
scanf() is less dangerous than fgets(), be prepared to lose that
argument.) Assuming a bug-free conforming implementation, the choices
are A) use fgets() per its documentation and take precautions on par
with those required for the safe use of virtually all other
non-trivial library functions, or B) implement your own replacement
for fgets(), which will invariably include caveats for safe use on the
order those necessary to use fgets() and any number of other library
functions. Option B certainly seems to call for a more advanced
programmer than A.
In practise these steps are seldom followed. The degree of danger obviously
depends on the application, whether it is possible for the input to be
sabotaged by some malicious person with access to the source. But it is
certainly there.

A simple strcpy() call can easily be "dangerous" in a completely
non-obvious way; I'm presuming you aren't going to claim that
strcpy() is impossibly dangerous for all but the best programmers.
 

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,774
Messages
2,569,598
Members
45,149
Latest member
Vinay Kumar Nevatia0
Top