Why is it dangerous?

J

Julian

'evening.

I'm not new to C and have been programming in it since I was 8 but
here's a strange problem I've never seen before.

When I compile a program from our C course with a windows compiler
there is no problem but when I try to compile it with a linux compiler
it complains that

a_03.c:(.text+0x4d): warning: the `gets' function is dangerous
and should not be used.

Is linux more dangerous than windows? Where can I download a
non dangerous gets function? I have never used gets before is
there undefined behavior somewhere?


Here is a trimmed down example program from my assignment that
demonstrates the problem

#include <stdio.h>
#include <malloc.h>

void main()
{
char *string;
printf("enter string (max 2000 chars): ");
fflush(stdin);
fflush(stdout);
string = (char *)malloc(2001);
if(!string) exit(1);
gets(string);
printf("you entered: %s\n", string);
free(string);
exit(0);
}

On windows with TurboC and Lcc no error is printed. On linux with
gcc it says gets is dangerous.

Please advise my instructor says gcc is overly pedantic.
 
I

Ian Collins

Julian said:
Please advise my instructor says gcc is overly pedantic.
As Richard said, the opposite is true unless you invoke gcc with the
correct options. That's why it has a -pedantic option!

As a learner using gcc, you should use

gcc -ansi -Wall -pedantic

as a minimum set of options. Substitute '-std=c99' for '-ansi' if you
are learning C99.
 
S

s0suk3

'evening.

I'm not new to C and have been programming in it since I was 8 but
here's a strange problem I've never seen before.

When I compile a program from our C course with a windows compiler
there is no problem but when I try to compile it with a linux compiler
it complains that

a_03.c:(.text+0x4d): warning: the `gets' function is dangerous
and should not be used.

Is linux more dangerous than windows? Where can I download a
non dangerous gets function? I have never used gets before is
there undefined behavior somewhere?

Here is a trimmed down example program from my assignment that
demonstrates the problem

#include <stdio.h>
#include <malloc.h>

void main()
{
    char *string;
    printf("enter string (max 2000 chars): ");
    fflush(stdin);
    fflush(stdout);
    string = (char *)malloc(2001);
    if(!string) exit(1);
    gets(string);
    printf("you entered: %s\n", string);
    free(string);
    exit(0);

}

On windows with TurboC and Lcc no error is printed. On linux with
gcc it says gets is dangerous.

Please advise my instructor says gcc is overly pedantic.

(Leaving aside all the errors in the code that other people have
already pointed out and will continue to point out...)

It has nothing to do with the operating system, it has nothing to do
with the compiler, it has nothing to do with your instructor; it has
to do with gets(), and gets() alone (and you can't get a "safer"
gets(), BTW). The problem is that gets() has no way to know the size
of the buffer you pass to it, and it will continue to read until a
newline. You allocated 2001 bytes, which is reasonably large enough
for a line of text. But... suppose a cracker gets to your program and
gives you this line on the terminal:

enter string (max 2000 chars):
111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

Those are 2001 characters. There you go, the cracker overflowed your
buffer.

Sebastian
 
K

Keith Thompson

Julian said:
#include <stdio.h>
#include <malloc.h>

void main()
{
char *string;
printf("enter string (max 2000 chars): ");
fflush(stdin);
fflush(stdout);
string = (char *)malloc(2001);
if(!string) exit(1);
gets(string);
printf("you entered: %s\n", string);
free(string);
exit(0);
}
[...]

This program, in 16 lines, exhibits at least 6 blatant errors or
gratuitous non-portabilities that have been discussed repeatedly in
this newsgroup: <malloc.h>, "void main()", "fflush(stdin), casting the
result of malloc(), exit(1), and of course the use of gets().

Either this is deliberate, and Julian is a troll, or it's not, and
he's been very poorly taught. In the latter case, Julian, please read
read the comp.lang.c FAQ <http://www.c-faq.com/>, and feel free to
post again if you still have any questions.
 
S

santosh

CBFalconer said:
Correction: That omits many useful tests. I suggest:

gcc -W -Wall -ansi -pedantic

for better error detection.

I would also recommend:

-Wfloat-equal
-Wshadow
-Wpointer-arith
-Wbad-function-cast
-Wcast-qual
-Wcast-align
-Wwrite-strings
-Wstrict-prototypes
-Wold-style-definition
-Wmissing-prototypes
-Wredundant-decls
-Wunreachable-code
 
H

Harald van Dijk

CBFalconer said:
Correction: That omits many useful tests. I suggest:

gcc -W -Wall -ansi -pedantic

for better error detection.

I would also recommend:
[...]
-Wwrite-strings

I would not, since it deliberately makes the compiler nonconforming. For
those that understand in what ways, it can be useful, but they can find
the option themselves. CBFalconer included that option in his
recommendations recently, and I'm glad he dropped it.
 
S

santosh

Harald said:
CBFalconer said:
Correction: That omits many useful tests. I suggest:

gcc -W -Wall -ansi -pedantic

for better error detection.

I would also recommend:
[...]
-Wwrite-strings

I would not, since it deliberately makes the compiler nonconforming.
For those that understand in what ways, it can be useful, but they can
find the option themselves. CBFalconer included that option in his
recommendations recently, and I'm glad he dropped it.

Thanks for that. I do remember that subthread now, but I passed over it,
being pressed for time. Now, to the Google Groups archive...
 
I

Ian Collins

Harald said:
CBFalconer said:
Correction: That omits many useful tests. I suggest:

gcc -W -Wall -ansi -pedantic

for better error detection.
I would also recommend:
[...]
-Wwrite-strings

I would not, since it deliberately makes the compiler nonconforming. For
those that understand in what ways, it can be useful, but they can find
the option themselves. CBFalconer included that option in his
recommendations recently, and I'm glad he dropped it.

Even so, it would save a lot of noise here if it where the default in gcc!
 
B

Ben Bacarisse

Malcolm McLean said:
This is a hardy annual.
Of course fgets() can be used safely, but won't be. For instance
Richard Heathfield posted a dangerous use of fgets() in this very
thread. It will give the wrong answer if the user enters a string of
over 2000 characters.

You have allowed yourself to slip into polemic. It is not clear, at
least to me, what the right answer is so you are stretching the point
-- be careful with fgets and long lines -- by saying that the answer
is "wrong" and the use "dangerous".
 
A

Antoninus Twink

Julian said:

The functionality of gets() is defined by ISO; it takes a pointer to
the first character in a buffer, and stores an entire line from stdin
into that buffer, *regardless of the buffer's size*!! There is no safe
way to use such a function.

Of course, this is nonsense. There is a perfectly safe way to use
gets(), namely by being in control of what appears on stdin. Here in the
real world, people write all sorts of scraps of in-house code to run
once and forget about. They use fscanf() without elaborate error
checking, because they are 100% sure of the format of the input files.
gets() is no different.

Of course, in any production code, or any code at all where someone
other than the programmers will be able to decide what appears on stdin,
then gets() should not be used, the return value of p=malloc(10) should
be checked, etc. etc.

Instead of gets(), use whatever safe function is available on your
platform. For example, on GNU systems there is a getline() function
provided by stdio.h, which will dynamically allocated a big enough
buffer using malloc(). Or, roll your own getline function if portability
is a big issue for you.
 
C

CBFalconer

santosh said:
I would also recommend:

-Wfloat-equal
-Wshadow
-Wpointer-arith
-Wbad-function-cast
-Wcast-qual
-Wcast-align
-Wwrite-strings
-Wstrict-prototypes
-Wold-style-definition
-Wmissing-prototypes
-Wredundant-decls
-Wunreachable-code

I wouldn't, although those may be useful. The OP is obviously a
newbie, and is not going to remember all that. It is only useful
when implemented via an alias, a script, or a makefile, etc. What
I recommended is a minimum to ensure reasonably correct standard C
code.
 
C

CBFalconer

santosh said:
Harald said:
santosh said:
CBFalconer wrote:

Correction: That omits many useful tests. I suggest:

gcc -W -Wall -ansi -pedantic

for better error detection.

I would also recommend:
[...]
-Wwrite-strings

I would not, since it deliberately makes the compiler nonconforming.
For those that understand in what ways, it can be useful, but they
can find the option themselves. CBFalconer included that option in
his recommendations recently, and I'm glad he dropped it.

Thanks for that. I do remember that subthread now, but I passed over
it, being pressed for time. Now, to the Google Groups archive...

I didn't drop it. I conceded your 'non-standard' point. I
maintain that, for new code, including it will result in better
code, and maintain conformity. It may object to some actually
conforming code.
 
R

Richard

Richard Heathfield said:
Julian said:


No. Your Linux compiler warned you about a dangerous function that should
never be used.

Total and utter nonsense. C is used all over the place for creating
elements which are under strict control and the program/process/function
has a totally controlled and defined input stream. In those scenarios
gets is used flawlessly in millions of programs around the world.

if you can NOT define the input then I would agree. But in the real
world the input is indeed guarenteed in a properly functioning
system. if the system isn't well defined then all "bets are off" since
you can pretty much be sure that undefined behaviour/input has already
compromised the process pipeline.
 
C

CBFalconer

Malcolm said:
This is a hardy annual. Of course fgets() can be used safely, but
won't be. For instance Richard Heathfield posted a dangerous use of
fgets() in this very thread. It will give the wrong answer if the
user enters a string of over 2000 characters. Of course it is not
dangerous in a little exercise program that doesn't do anything,
but then neither is gets().

To use fgets() safely you must check for the newline. If it is not
present a buffer overflow occurred. So you must then take action
against the buffer to ensure that the next read doesn't get the
remainder of the previous line.

Or just get the remainder of the line. No overflow has occurred.

And you can avoid all those problems by using the (released to
public domain) ggets() function, available in standard C source
form at:

<http://cbfalconer.home.att.net/downlod/ggets.zip>

ggets gets complete lines, is safe, and has the simplicity of
gets. Malicious users can run the system out of assignable heap
memory, but will normally have to work hard to do so.
 
S

santosh

Richard said:
Total and utter nonsense. C is used all over the place for creating
elements which are under strict control and the
program/process/function has a totally controlled and defined input
stream. In those scenarios gets is used flawlessly in millions of
programs around the world.

if you can NOT define the input then I would agree. But in the real
world the input is indeed guarenteed in a properly functioning
system. if the system isn't well defined then all "bets are off" since
you can pretty much be sure that undefined behaviour/input has already
compromised the process pipeline.

I wonder, can you give examples of sources of perfectly controlled and
defined input? Certainly disk files can be tampered, as can pipes,
sockets and almost every other device. Why risk it with gets when fgets
is just as easy and safer?
 
A

Antoninus Twink

CBFalconer said:
Correction: That omits many useful tests. I suggest:
gcc -W -Wall -ansi -pedantic
for better error detection.

I would also recommend:
[...]
-Wpointer-arith

This is redundant, since it's already enabled by -pedantic.
 
A

Antoninus Twink

I wonder, can you give examples of sources of perfectly controlled and
defined input? Certainly disk files can be tampered, as can pipes,
sockets and almost every other device.

True. The world might also be destroyed in a nuclear holocaust while
your throwaway program is reading its non-life-critical data, so why
take the risk of programming at all? Drink a beer, get laid, and wait
for the mushroom cloud to take you.
 
R

Richard

santosh said:
I wonder, can you give examples of sources of perfectly controlled and
defined input? Certainly disk files can be tampered, as can pipes,
sockets and almost every other device. Why risk it with gets when fgets
is just as easy and safer?

If I have a well defined pipeline then any deviance make the entire line
corrupt.

If I have a process whose DEFINED input is say, 16 characters at a time
on its standard input then its not its job to ensure thats what
comes. Dont believe me? Try calling strcpy with NULL pointer as the
destination.

Since it has NO way of reporting back errors to the program feeding it,
what should me module do? Carry on processing this rogue data?

The point is this - one can worry all day long. Once can also be
practical and "real".

Its like the malloc business. If malloc fails for a few bytes the chance
of that program not exhibiting "Undefined Bahvaiour" because you checked
the return code is practically nil.
 
N

Nick Keighley

Total and utter nonsense. C is used all over the place for creating
elements which are under strict control and the program/process/function
has a totally controlled and defined input stream. In those scenarios
gets is used flawlessly in millions of programs around the world.

if you can NOT define the input then I would agree. But in the real
world the input is indeed guarenteed in a properly functioning
system.

hardly. Much web based software does not have total control
of its inputs. Compilers don't have TCOI. Even if the other end of
your
"link" is "trusted" there can be errors made. Yes, you test your
software but
why not on the length of input
if the system isn't well defined then all "bets are off" since
you can pretty much be sure that undefined behaviour/input has already
compromised the process pipeline

how many bugs has gets() caused? Windows certainly. Wasn't the Unix
worm gets() based?
 
S

Serve Lau

Antoninus Twink said:
True. The world might also be destroyed in a nuclear holocaust while
your throwaway program is reading its non-life-critical data, so why
take the risk of programming at all? Drink a beer, get laid, and wait
for the mushroom cloud to take you.

I agree except on one thing. I'd drink the beer last
 

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,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top