views:

206

answers:

10

When we define a character array as 'char name[10]', this indicate that the array 'name' can hold a string of length ten character. But in the program shown below the array name can hold more than ten characters. How is this possible?

//print the name of a person.  
char name[10];  
scanf("%s",name);  
printf("%s",name);  

Here if I enter a name even of length greater than ten character, there is no run time error and the program prints all the characters I have entered. There is a program termination if I enter the name of twenty or more characters.

Note: I am running the program on Ubuntu9.04 using a gcc compiler.

+4  A: 

With an array of size 10 chars, to represent a string in C You can really only use 9 characters and the null terminated character. If you use more than 9 characters (+1 termination) then you'll have undefined behavior.

You are simply overwriting memory that you shouldn't be. What happens whether segfault, or working as you expect is as good as random.

Brian R. Bondy
+4  A: 

Your code invokes Undefined Behavior. Never use scanf() to read a string, use fgets() instead.

scanf() and gets() have the exact same problem with memory overrun. You can easily read in more characters than your char[] can hold.

Prasoon Saurav
Still, IIRC, in scanf you can limit the characters read using a width specifier (e.g., "%9s" in this very case).
Matteo Italia
-1 for incorrect information about `scanf`, which has perfectly usable field width specifiers.
R..
@R..: It's true that you can avoid buffer overflows with `scanf`, but it's still simpler to avoid `scanf` completely, and doing so will avoid other `scanf` problems.
jamesdlin
@R: Sorry, deleted my comment. :-)
Prasoon Saurav
A: 

This is called overflow.

Praveen S
buffer overflow
Brian R. Bondy
A: 

You are exploiting undefined behaviour therefore anything can happen - program can crash or keep running normally or start doing something weird.

qrdl
+7  A: 

Because scanf doesn't know how long the array is. The variable "name" is not of type "array" but of type "pointer" (or "address"). It says, start writing here and keep writing until you're done. You may be lucky and have some other not-as-critical stuff on your stack that gets overwritten, but eventually, scanf will write and write and overwrite something fatal, and you'll get a Segmentation Fault. That's why you must always pass the size of arrays around.

It's akin to giving a blind person a pencil and saying "start writing here", without them being able to see where the end of the paper is. They will eventually write on the table and damage something. (Note: this is not a knock on the blind, this is just a metaphor.)

In the above case, I highly recommend using fgets() to grab a specific amount from stdin, and then sscanf() to pull whatever information from that line and put it into separate variables as needed. Scanf() and fscanf() are evil, I have never found a use for them that fgets()+sscanf() can't more safely solve.

char line[1024]; /* arbitrary size */
if( fgets( line, 1024, stdin ) != NULL )
{
  fprintf( stdout, "Got line: %s", line );
}

Or for things beyond strings:

# cat foo.c
  #include <stdio.h>
  int main( int argc, char **argv )
  {
    int i;
    char line[1024];
    while( fgets( line, 1024, stdin ) != NULL )
    {
      if( sscanf( line, "%d", &i ) == 1 )
      { /* 1 is the number of variables filled successfully */
        fprintf( stdout, "you typed a number: %d\n", i );
      }
    }
  }
# gcc foo.c -o foo
# ./foo
  bar
  2
  you typed a number: 2
  33
  you typed a number: 33
  <CTRL-D>
eruciform
+1  A: 

C has no checks on array length. It will allow you to overflow an array.

In you case there happens to be writable memory after the array so you don't crash if you overflow by a small amount (although who knows that you are corrupting).

Try this code and see what happen when you put in more than 10 characters.

char name[10];
char name2[10];  
scanf("%s",name);  
printf("%s",name);  
printf("%s",name2); 

Also the name array can hold 9 characters, the 10th needs to be the terminating null zero '\0'

shf301
This is creating a Stack Smash as soon as I enter the name of more than ten Character. Previously I was getting the same message "Stack Smash" after I entered twenty characters.Can you please make it a bit more clear...?
Mohit
@MohitYou need to understand that you cant add more than 9 chars to the string name,name2 etc. They are declared to hold a string with a maximun length of 9. Otherwise it results in corruption. Sometimes it crashes immediately. Sometimes it overwrites the adjacent memory place. But when new request for memory arrives the adjacent memory may be allocated. Hence it corrupts the initial memory.
Praveen S
shf301
@shf301: You have name and name2 reversed.
ninjalj
@junjalj - it really depends on how the compiler chooses to layout the fields, but that could work.
shf301
A: 

When you say char c[10] you allocate 10 bytes for that variable. However, your program might "own" subsequent bytes as well, that's why you may not get a segfault. But you will run in to so many other problems you wish you had got a segfault.

Andreas Jansson
+2  A: 

Welcome to C world...

  • C does not perform array bounds checking;
  • the name of an array is nothing else than a pointer to the first element of the array;
  • scanf (as used in Mohit example program) does not handle destination buffer size limit;
  • with a wrong pointer value you can write anywhere in memory and you should expect unpredictable behaviour, segmentation fault if you are lucky.
Vanni Totaro
`scanf` **does** handle buffer size limit; you just have to tell it what the limit is...
R..
@`R..`: how pedantic! Obviously I meant `scanf` as used in `Mohit` program. Let me edit the post, or someone else will take the commitment to downvote it again...
Vanni Totaro
+1  A: 

How is this possible?

The array is allocated on the stack. Following it there may be empty space or data that is of less than national-security importance (e.g., callee-saves registers that are not actually used in the caller). Eventually if the name you enter is long enough, you overwrite something important. Including, under some compilers, the return address!

Running the program under valgrind will detect an overrun error instantly.

Norman Ramsey
+1  A: 

scanf allows for a maximum width specifier, as in

scanf("%9s", name);

This will read up to 9 characters and add a terminating NUL character, for a total of 10 characters.

What happens if you don't limit the amount of characters scanf can read? Well, then your string ends up overwriting something else. In this case, I guess your buffer is on the stack, so you overwrite something on the stack. The stack holds local variables, return addresses (to the function that called this function), and function arguments. Now, a malicious user could fill that buffer with arbitrary code, and overwrite the return address with the address of that code (there are many variants of this attack). A malicious user could execute arbitrary code through that program.

ninjalj
Helped a Lot. I didn't know about %9s thing. Thanks for the info.
Mohit