1

If successful, the gets function returns its argument. But when I use the return value in printf, it occurs segmentation fault. The code that occurs error is below.

#include  <stdio.h>
 
#define MAX_LINE 100
 
int main(void)
{
   char line[MAX_LINE];
   char *result;
 
   printf("Please enter a string:\n");
   if ((result = gets(line)) != NULL)
      printf("The string is: %s\n", result); // Segmentation fault.
   else if (ferror(stdin))
      perror("Error");
}
/*** output ***
Please enter a string:
abc
Segmentation fault (core dumped)
*/

But if I use the argument of the gets function to print input, the error goes away.

      /* -- snip -- */
      printf("The string is: %s\n", line); // correct

In the case of the fgets function, there is no error when using the return value. Below is the fgets function code.

#include <stdio.h>
 
#define  MAX_LEN  100
 
int main(void)
{
   FILE *stream;
   char line[MAX_LEN], *result;
 
   stream = fopen("mylib/myfile","rb");
 
   if ((result = fgets(line,MAX_LEN,stream)) != NULL)
      printf("The string is %s\n", result); // correct
 
   if (fclose(stream))
      perror("fclose error");
}

If successful both function gets and fgets, both functions return the first argument char *str. Why would segmentation fault happen only in the gets function?

Above code is from https://www.ibm.com/docs/en/i/7.3?topic=functions-gets-read-line and https://www.ibm.com/docs/en/i/7.3?topic=functions-fgets-read-string#fgets

My environment is gcc 8.4.0.

Below is a warning message.

test.c: In function ‘main’:
test.c:11:18: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
    if ((result = gets(line)) != NULL)
                  ^~~~
                  fgets
test.c:11:16: warning: assignment to ‘char *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    if ((result = gets(line)) != NULL)
                ^
/tmp/ccuOAqAp.o: In function `main':
test.c:(.text+0x30): warning: the `gets' function is dangerous and should not be used.
(base) sh@sh-550P5C-550P7C:~/exercises/dummies/cpp$ gcc test.c
test.c: In function ‘main’:
test.c:11:18: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
    if ((result = gets(line)) != NULL)
                  ^~~~
                  fgets
test.c:11:16: warning: assignment to ‘char *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
    if ((result = gets(line)) != NULL)
                ^
/tmp/ccQIks7u.o: In function `main':
test.c:(.text+0x30): warning: the `gets' function is dangerous and should not be used.
Sihyeon Kim
  • 161
  • 7
  • Did you get any warnings when you compiled the code? – kaylum Jul 04 '21 at 05:32
  • 3
    Never use `gets`, it is no longer part of the standard C library. Please read [Why is the gets function so dangerous that it should not be used?](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used) – Weather Vane Jul 04 '21 at 05:43

1 Answers1

2

gets has been removed from the C11 standard. Unfortunately the way it is implemented can cause the exact problem in this question. The gets declaration was removed from the stdio.h header but the definition/implementation is still present in libc. That's essentially what this warning is telling you (and illustrates why you should never ignore warnings):

test.c: In function ‘main’:
test.c:11:18: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
    if ((result = gets(line)) != NULL)

For implicit declarations C assumes the function returns int. But in this case the function actually returns char *. For a 64 bit binary int is 32 bit and char * is 64 bit. Hence the return value will be incorrectly truncated and result in a seg fault when the invalid address is accessed.

The bottom line - don't use gets. Use fgets instead. See: Why is the gets function so dangerous that it should not be used?

If you really must use gets then the workaround is to compile with -std=c99 or manually declare gets prototype.

kaylum
  • 13,833
  • 2
  • 22
  • 31