Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why char name[1] can hold more than 1 character? [duplicate]

I was doing a little bit of research about a topic when I came across this situation. Assume the following C code:

#include <stdio.h>
int main() {
char name[1];
scanf("%s",name);
printf("Hi %s",name);
return 0;
}

I've compiled with -fno-stack-protector and tested it with input longer than 1, like John, & to my surprise, It works!
Shouldn't it throw a segmentation fault when the input is longer than 1?
Eventually it broke with Alexander as input (9) but it works with anything less than 9.
Why is it working with inputs longer than the name array length?
P.S : I'm using Ubuntu(64-bit), gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04) & CLion as IDE.

like image 665
Sam Avatar asked Feb 10 '23 10:02

Sam


2 Answers

This is undefined behavior. Your program has a buffer overrun, because it allocates exactly one character, which is sufficient for storing an empty null-terminated string.

However, there is memory adjacent to your buffer that has not been allocated to your program. scanf places your input into that memory, because it does not know how long is your string buffer. This is a big danger and a source of countless hacker attacks, when a pre-determined sequence of bytes is placed into your string, in hopes to override some vital elements, and eventually gain control.

That is why using %s without specifying the size is dangerous. You need to always add a proper size limit to %s, otherwise your program is in danger of buffer overrun.

char name[120];
scanf("%119s",name);

This program is safe, because even if a malicious user types more than 120 characters, scanf would ignore everything past 119-th character, as specified in %119s format.

like image 169
Sergey Kalinichenko Avatar answered Feb 20 '23 10:02

Sergey Kalinichenko


The size and type of the variable where you store the input has nothing to do with scanf.

scanf is only passed an address (pointer) where to deposit the input it gets from the user.

Clever compilers now warn you if the format string passed to scanf does not match the type of the parameters, but in principle you could even declare name as an integer:

int name;

and it would hold the input string quite well, up to three characters (the fourth is for the End Of String, i.e. zero), assuming the size of int is 32 bits , i.e. 4 bytes

The fact that it works is pure bad luck, since the input data, when stored by scanf, runs past the end of the allocated buffer for it (name).

Note: allocating only one character for a string would never work, even for input strings of one character only. You always need to account for the EOS that is used to terminate them. So name should be declared as char name[2]; at the very least.

like image 43
Pynchia Avatar answered Feb 20 '23 10:02

Pynchia