Safe version of gets

A

Anthony Irwin

Hi,

I am fairly new to C and all the C books I got talk about gets() but when
I compile it says I should not use gets() because it is dangerous. I
understand that it is dangerous because it doesn't check whether there is
more characters entered by the user the what can be stored but I don't
know what the safe equivalent of gets() is.

Below is an example program I have written. (GCC is my compiler on
GNU/Linux system.)

Kind Regards,
Anthony Irwin

#include <stdio.h>

char histogram[50];
int i, space, begin, length;

int main() {
printf("\nEnter some words for the histogram: ");
sgets(histogram);
printf("\n\n");
begin = 1;
length = strlen(histogram);

for (i = 0; i <= length; i++) {
if (histogram != '\0') {
if (space == 1 || begin == 1) {
histogram = toupper(histogram);
begin = 0;
}
printf("\n\t%c", histogram);
printf("\t\t%d", i);

if (histogram == ' ') {
space = 1;
printf("\t\tSpace");
}
else {
space = 0;
}
}
}

return 0;
}
 
P

Peter Pichler

Anthony said:
I am fairly new to C and all the C books I got talk about gets() but when
I compile it says I should not use gets() because it is dangerous. I
understand that it is dangerous because it doesn't check whether there is
more characters entered by the user the what can be stored but I don't
know what the safe equivalent of gets() is.

fgets()
 
A

Anthony Irwin

Hi,

I am fairly new to C and all the C books I got talk about gets() but when
I compile it says I should not use gets() because it is dangerous. I
understand that it is dangerous because it doesn't check whether there is
more characters entered by the user the what can be stored but I don't
know what the safe equivalent of gets() is.

Below is an example program I have written. (GCC is my compiler on
GNU/Linux system.)

Kind Regards,
Anthony Irwin

#include <stdio.h>

char histogram[50];
int i, space, begin, length;

int main() {
printf("\nEnter some words for the histogram: ");
sgets(histogram);

Above is actually gets(histogram); I was making changes before I posted
and missed it sgets doesn't exist with gcc or ansi c.
printf("\n\n");
begin = 1;
length = strlen(histogram);

for (i = 0; i <= length; i++) {
if (histogram != '\0') {
if (space == 1 || begin == 1) {
histogram = toupper(histogram);
begin = 0;
}
printf("\n\t%c", histogram);
printf("\t\t%d", i);

if (histogram == ' ') {
space = 1;
printf("\t\tSpace");
}
else {
space = 0;
}
}
}

return 0;
}
 
S

Suman

Peter said:

gets() works (or not) on stdin. So, to be accurate:
fgets( histogram, sizeof histogram, stdin );

[1] variable histogram from code posted by OP

Read up on this function, it's something like --
"The fgets() function reads at most n-1 characters from stream into the
buffer pointed to by s. No additional characters are read after fgets()
has read and transferred a newline character to the buffer. A null
character is written immediately after the last character that fgets()
reads into the buffer."
 
V

Villy Kruse

Hey thanks I can do the following:

fgets(histogram,sizeof(histogram), stdin);

Don't forget to handle the trailing newline character, and do realise
that if there is no trailing new line, your record is truncated, in which
case the following fgets will get you the rest of the line. Of cours,
if the last line doesn't have a new line your last line read from the
file may not have a new line, which you also need to deal with.

Villy
 
M

Martin Ambuhl

Anthony said:
Hi,

I am fairly new to C and all the C books I got talk about gets()

Burn them. Where did you get "all the C books" that use gets()?
but when
I compile it says I should not use gets() because it is dangerous.

That's right.
I
understand that it is dangerous because it doesn't check whether there is
more characters entered by the user the what can be stored but I don't
know what the safe equivalent of gets() is.

fgets() is much safer. And you can always roll your own.
 
C

CBFalconer

Anthony said:
I am fairly new to C and all the C books I got talk about gets()
but when I compile it says I should not use gets() because it is
dangerous. I understand that it is dangerous because it doesn't
check whether there is more characters entered by the user the
what can be stored but I don't know what the safe equivalent of
gets() is.

Download and use the portable public domain ggets module at:

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

akarl

Anthony said:
Hi,

I am fairly new to C and all the C books I got talk about gets() but when
I compile it says I should not use gets() because it is dangerous. I
understand that it is dangerous because it doesn't check whether there is
more characters entered by the user the what can be stored but I don't
know what the safe equivalent of gets() is.

Below is an example program I have written. (GCC is my compiler on
GNU/Linux system.)

Why don't you tell us (exactly) what the program does/is supposed to do?

August
 
W

wolfman

I wrote a function, that I always use: (shure you have to include stdio.h)

int mygets(FILE *stream, char *buffer, int lim)
{ int i = 0, c;

while (i < lim - 1 && (c = getc(stream)) != EOF && c != '\n')
{ *buffer++ = (char) c;
i++;
}
*buffer = 0; /* or better *buffer = '\0' in non ASCII / ANSI Systems */
return i;
}

Parameters:
stream: I/O-Stream or FILE-Pointer
buffer: pointer to text buffer in memory
lim: buffer size

Return value:
Function returns the number of read characters

Remarks:
- If you use 16-bit characters you have to change the datatype char to the
appropriate datatype of your system,
for example wchar.
- You don't have to care about terminating zeros. The function always adds
one.

Best regards,
wolfman
 
M

Malcolm

Martin Ambuhl said:
fgets() is much safer. And you can always roll your own.
Actually it's more dangerous, unless the programmer really knows what he is
doing.
Undefined behaviour is usually correct behaviour, terminating the program
with an appropriate message. Silently truncating input will usually produce
incorrect behaviour.
 
C

CBFalconer

wolfman said:
I wrote a function, that I always use: (shure you have to include
stdio.h)

int mygets(FILE *stream, char *buffer, int lim)
{ int i = 0, c;

while (i < lim - 1 && (c = getc(stream)) != EOF && c != '\n')
{ *buffer++ = (char) c;
i++;
}
*buffer = '\0';
return i;
}

Please don't toppost. Your answer belongs after (or intermixed
with) the material to which you reply, after snipping anything not
germane to your answer.

Problem, because the caller has no idea whether a '\n' was received
or not. The insidious advantage of gets is that it ALWAYS returns
a complete line, regardless of what that tramples over. My ggets
has the same advantage, without the trampling. Thus it is safe to
remove the terminal \n in the function.

Apart from the \n being returned, I see no essential difference
between your function and fgets. In interactive work it is
essential to know a line has been consumed.

My ggets has the prototype:

int ggets(char **ln);

returning non-zero for error/EOF, and is called with:

char *ln;

result = ggets(&ln);
or
result = fggets(&ln, file);

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

(The cost is that you have to free(ln) when done with it)
 
C

Chris Torek

Actually it's more dangerous, unless the programmer really knows
what he is doing. Undefined behaviour is usually correct behaviour ...

Except for the fact that it is not.
terminating the program with an appropriate message.

Most often, undefined behavior leads to bugs in Microsoft products
that result in viruses, worms, "zombie" PCs, and spam.

Much of your spam is due to gets() calls (or equivalent). (Most
of the rest is due to other bugs in IIS.)
Silently truncating input will usually produce
incorrect behaviour.

But observable, repeatable, predictable incorrect behavior.
Moreover, programs that use gets() in this same way also
silently truncate input:

gets(buf); /* XXX bad */
error = FALSE;
...

Since the "error" variable happens to alias &buf[sizeof buf], this
truncates the input, silently. In other words, the function you
claim to be "superior" has the same flaw as fgets(), plus additional
flaws.
 
A

Anton Petrusevich

CBFalconer said:
My ggets has the prototype:
int ggets(char **ln);

Great. What if I use your ggets() in my program and someone will run it
as ./myprogram </dev/zero? Sorry I didn't look into your code, but I
suppose it will eat all available memory and then crash, right?
 
G

Giannis Papadopoulos

Anton said:
CBFalconer wrote:




Great. What if I use your ggets() in my program and someone will run it
as ./myprogram </dev/zero? Sorry I didn't look into your code, but I
suppose it will eat all available memory and then crash, right?

But it won't crash... If you do 'rm -rf /' it is not the fault of the
creator of rm...

--
one's freedom stops where other's begin

Giannis Papadopoulos
http://dop.users.uth.gr/
University of Thessaly
Computer & Communications Engineering dept.
 
A

Anton Petrusevich

Giannis said:
But it won't crash... If you do 'rm -rf /' it is not the fault of the
creator of rm...

rm -rf / must be executed with root privileges, but ./myprogram does not
require that. "Analogies suck" (c). I just wanted to show that such a
simple API have some drawbacks.
 
G

Giannis Papadopoulos

Anton said:
Giannis Papadopoulos wrote:




rm -rf / must be executed with root privileges, but ./myprogram does not
require that. "Analogies suck" (c). I just wanted to show that such a
simple API have some drawbacks.

Ok, then 'rm -rf ~'..
You can't (and shouldn't always) protect a system from a complete idiot.

There are numerous programs out there that if they had available memory,
they would work with infinite input.

And ggets() doesn't crash.. A well-written program in a well-written
system would notify that memory allocation failed, return EXIT_FAILURE
and the os would deallocate the memory. If you choose win98, then BSOD
is the solution..

Have you ever tried while(1) {fork();}? Should fork check how many times
it is called? If not, why should CBFalconer bother to check how many
chars are read, seriously hindering perfomance?

--
one's freedom stops where other's begin

Giannis Papadopoulos
http://dop.users.uth.gr/
University of Thessaly
Computer & Communications Engineering dept.
 
C

CBFalconer

Anton said:
Great. What if I use your ggets() in my program and someone will run it
as ./myprogram </dev/zero? Sorry I didn't look into your code, but I
suppose it will eat all available memory and then crash, right?

Yes, it will eat all memory. No, it won't crash. It will return
an error indicator. If the caller then executes free(ln) the
memory will be available again. This assumes /dev/zero returns an
unending stream of zero bytes.
 

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,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top