1

Given the following program:

#include <stdio.h>

int main()
{
    char buf[1024];
    scanf("%s", buf);
    printf("----> %s", buf);
    return 0;
}

which is executed as follows:

grep ....| a.out

or

echo ....| a.out

I get a Segmentation fault error. Can anyone explain why?

David Pfeffer
  • 38,869
  • 30
  • 127
  • 202
thlgood
  • 1,275
  • 3
  • 18
  • 36

3 Answers3

7

Whatever you are echoing or grepping must contain more than 1023 characters. (1024 - 1 for the null terminator.)

Instead of using scanf, use fgets and specify a size. Alternatively, use scanf but specify the field length. You can do scanf("%1023s", buf);. If there's more bytes available, you can always do it again to read in the rest.

Given your test input, you should not receive a segfault. I just tried it locally and it worked fine. If you are on Linux, since you wrote a.out instead of ./a.out, depending on how your path is configured you may be running the wrong program (some sort of a.out in your bin folder?)

David Pfeffer
  • 38,869
  • 30
  • 127
  • 202
  • no..I run `echo 'This is'|a.out` it still got `Segmentation fault` – thlgood Feb 17 '12 at 13:27
  • `fscanf` provides no more protection than `scanf`, it's just `scanf` using an explicit file handle rather than `stdin` - I think you meant `fgets` which _does_ have a limit on characters read. – paxdiablo Feb 17 '12 at 13:47
2

Don't ever use scanf with unbounded strings. fgets provides a much safer alternative, especially if you provide an intelligent wrapper function like the one in this answer.

I'm assuming that's just sample code here but, just in case it isn't, you can achieve the same effect with:

WhateverYourCommandIs | sed 's/^/----> '

without having to write your own tool to do the job. In fact, with sed, awk and the likes, you probably never need to write text processing tools yourself.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
0

from scanf man:
s Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null character ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.

specifying maximum field width will prevent stack overrun

    scanf("%1023s", buf);

and to ensure stack no overrun on printf use memset:

    memset(buf,0,1024);

so, programm will be:

#include <stdio.h>
#include <string.h>
int main()
{
    char buf[1024];
    memset(buf,0,1024);
    scanf("%1023s", buf);
    printf("----> %s", buf);
    return 0;
}
2r2w
  • 1,384
  • 1
  • 12
  • 29
  • memset is not needed since we can initialise arrays to 0 easily in C99-C11. It's also probably faster, but that depends on system implementation. – Tomas Pruzina Feb 17 '12 at 13:59
  • 1
    @thlgood: Why is this the accepted answer? This clearly didn't answer the question, whereas I found the problem. – David Pfeffer Feb 17 '12 at 20:13